以前学习swift时的我的笔记,根据github:the-swift-programming-language-in-chinese学习、总结,将重要的内容提取,加以理解后整理为学习笔记,方便之后查询用。详细能够参考the-swift-programming-language-in-chinese,或者苹果官方英文版文档html
当前版本是swift2.2ios
扩展 就是为一个已有的类、结构体、枚举类型或者协议类型添加新功能。这包括在没有权限获取原始源代码的状况下扩展类型的能力(即 逆向建模 )。扩展和 Objective-C 中的分类相似。(与 Objective-C 不一样的是,Swift 的扩展没有名字。)git
若是你经过扩展为一个已有类型添加新功能,那么新功能对该类型的全部已有实例都是可用的,即便它们是在这个扩展定义以前建立的。github
扩展能够为已有类型添加计算型实例属性和计算型类型属性。不能够添加存储性属性swift
扩展能够为已有类型添加新的构造器。这可让你扩展其它类型,将你本身的定制类型做为其构造器参数,或者提供该类型的原始实现中未提供的额外初始化选项。数组
扩展能为类添加新的便利构造器,可是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须老是由原始的类实现来提供。安全
扩展能够为已有类型添加新的实例方法和类型方法。app
经过扩展添加的实例方法也能够修改该实例自己。结构体和枚举类型中修改 self 或其属性的方法必须将该实例方法标注为 mutating,正如来自原始实现的可变方法同样。ide
下面的例子为 Swift 的 Int 类型添加了一个名为 square 的可变方法,用于计算原始值的平方值:函数
extension Int { mutating func square() { self = self * self } }
扩展能够为已有类型添加新下标。这个例子为 Swift 内建类型 Int 添加了一个整型下标。该下标 [n] 返回十进制数字从右向左数的第 n 个数字:
123456789[0] 返回 9
123456789[1] 返回 8
扩展能够为已有的类、结构体和枚举添加新的嵌套类型:
若是你在协议中定义了一个实例方法,该方法会改变采纳该协议的类型的实例,那么在定义协议时须要在方法前加 mutating 关键字。这使得结构体和枚举可以采纳此协议并知足此方法要求。
将 mutating 关键字做为方法的前缀,写在 func 关键字以前,表示能够在该方法中修改它所属的实例以及实例的任意属性的值
实现协议中的 mutating 方法时,如果类类型,则不用写 mutating 关键字。而对于结构体和枚举,则必须写 mutating 关键字。
协议能够要求采纳协议的类型实现指定的构造器。你能够像编写普通构造器那样,在协议的定义里写下构造器的声明,但不须要写花括号和构造器的实体:
protocol SomeProtocol { init(someParameter: Int) }
构造器要求在类中的实现
你能够在采纳协议的类中实现构造器,不管是做为指定构造器,仍是做为便利构造器。不管哪一种状况,你都必须为构造器实现标上 required 修饰符:
class SomeClass: SomeProtocol { required init(someParameter: Int) { // 这里是构造器的实现部分 } }
使用 required 修饰符能够确保全部子类也必须提供此构造器实现,从而也能符合协议。
构造器要求
协议能够要求采纳协议的类型实现指定的构造器。你能够像编写普通构造器那样,在协议的定义里写下构造器的声明,但不须要写花括号和构造器的实体:
protocol SomeProtocol {
init(someParameter: Int)
}
构造器要求在类中的实现
你能够在采纳协议的类中实现构造器,不管是做为指定构造器,仍是做为便利构造器。不管哪一种状况,你都必须为构造器实现标上 required 修饰符:
class SomeClass: SomeProtocol { required init(someParameter: Int) { // 这里是构造器的实现部分 } }
使用 required 修饰符能够确保全部子类也必须提供此构造器实现,从而也能符合协议。
若是一个子类重写了父类的指定构造器,而且该构造器知足了某个协议的要求,那么该构造器的实现须要同时标注 required 和 override 修饰符:
protocol SomeProtocol { init() } class SomeSuperClass { init() { // 这里是构造器的实现部分 } } class SomeSubClass: SomeSuperClass, SomeProtocol { // 由于采纳协议,须要加上 required // 由于继承自父类,须要加上 override required override init() { // 这里是构造器的实现部分 } }
若是类已经被标记为 final,那么不须要在协议构造器的实现中使用 required 修饰符,由于 final 类不能有子类
尽管协议自己并未实现任何功能,可是协议能够被当作一个成熟的类型来使用。
当一个类型已经符合了某个协议中的全部要求,却尚未声明采纳该协议时,能够经过空扩展体的扩展来采纳该协议:
struct Hamster { var name: String var textualDescription: String { return "A hamster named \(name)" } } extension Hamster: TextRepresentable {}
从如今起,Hamster 的实例能够做为 TextRepresentable 类型使用:
let simonTheHamster = Hamster(name: "Simon") let v1: TextRepresentable = simonTheHamster // 能够赋值 print(v1.textualDescription)
即便知足了协议的全部要求,类型也不会自动采纳协议,必须显式地采纳协议。
协议类型能够在数组或者字典这样的集合中使用,在协议类型提到了这样的用法。下面的例子建立了一个元素类型为 TextRepresentable 的数组:
let things: [TextRepresentable] = [game, d12, simonTheHamster]
以下所示,能够遍历 things 数组,并打印每一个元素的文本表示:
for thing in things { print(thing.textualDescription) } // A game of Snakes and Ladders with 25 squares // A 12-sided dice // A hamster named Simon
thing 是 TextRepresentable 类型而不是 Dice,DiceGame,Hamster 等类型,即便实例在幕后确实是这些类型中的一种。因为 thing 是 TextRepresentable 类型,任何 TextRepresentable 的实例都有一个 textualDescription 属性,因此在每次循环中能够安全地访问 thing.textualDescription。
协议可以继承一个或多个其余协议,能够在继承的协议的基础上增长新的要求。协议的继承语法与类的继承类似,多个被继承的协议间用逗号分隔:
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // 这里是协议的定义部分 }
你能够在协议的继承列表中,经过添加 class 关键字来限制协议只能被类类型采纳,而结构体或枚举不能采纳该协议。class 关键字必须第一个出如今协议的继承列表中,在其余继承的协议以前:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol { // 这里是类类型专属协议的定义部分 }
在以上例子中,协议 SomeClassOnlyProtocol 只能被类类型采纳。若是尝试让结构体或枚举类型采纳该协议,则会致使编译错误。
有时候须要同时采纳多个协议,你能够将多个协议采用 protocol<SomeProtocol, AnotherProtocol> 这样的格式进行组合,称为 协议合成(protocol composition)。你能够在 <> 中罗列任意多个你想要采纳的协议,以逗号分隔。
下面的例子中,将 Named 和 Aged 两个协议按照上述语法组合成一个协议,做为函数参数的类型:
protocol Named { var name: String { get } } protocol Aged { var age: Int { get } } struct Person: Named, Aged { var name: String var age: Int } func wishHappyBirthday(celebrator: protocol<Named, Aged>) { print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") }
协议合成并不会生成新的、永久的协议类型,而是将多个协议中的要求合成到一个只在局部做用域有效的临时协议中。
协议能够定义可选要求,采纳协议的类型能够选择是否实现这些要求。在协议中使用 optional 关键字做为前缀来定义可选要求。使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。好比,一个类型为 (Int) -> String 的方法会变成 ((Int) -> String)?。须要注意的是整个函数类型是可选的,而不是函数的返回值。