扩展:可以给一个现有的类,结构体,枚举,还有协议添加新的功能
1、添加计算型实例属性和计算型类属性
2、定义实例方法和类方法
3、提供新的构造器
4、定义下标
5、定义和使用新的嵌套类型
6、使已经存在的类型遵循(conform)一个协议
语法:使用 extension 关键字声明扩展
extension SomeType {
// 在这里给 SomeType 添加新的功能
}
扩展可以扩充一个现有的类型,给它添加一个或多个协议。
extension SomeType: SomeProtocol, AnotherProtocol {
// 协议所需要的实现写在这里
}
协议:
1、协议的定义:与类、结构体和枚举的定义非常相似
protocol SomeProtocol {
// 这里是协议的定义部分
}
2、遵循某个协议,各协议之间用逗号(,)分隔
struct SomeStructure: FirstProtocol, AnotherProtocol {
// 这里是结构体的定义部分
}
3、把父类放到协议前面
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 这里是类的定义部分
}
协议的属性要求:
1、只指定属性的名称和类型,并标明属性是 可读的 还是 可读可写的。
2、协议总是用 var 关键字来声明变量属性,在类型声明后加上 { set get } 来表示属性是可读可写的,可读属性则用 { get } 来表示:
protocol SomeProtocol {
var mustBeSettable: Int { get set } // 可读可写
var doesNotNeedToBeSettable: Int { get } // 只读
}
3、协议中定义类型属性使用 static 关键字。当类类型遵循协议时,除了 static 关键字,还可以使用 class 关键字来声明类型属性:
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
协议的方法要求:
1、遵循协议的类型要实现协议中定义的方法。协议中的方法不需要大括号和方法体。
2、可以在协议中定义具有可变参数的方法,和普通方法的定义方式相同。
3、不支持为协议中的方法提供默认参数。
4、协议中定义的类方法要使用 static 关键字
protocol SomeProtocol {
static func someTypeMethod()
}
协议的异变方法要求:
例如在值类型(即结构体和枚举)的实例方法中,使用 mutating 关键字的函数可以修改它所属的实例以及实例的任意属性的值。
1、如果协议中定义了实例方法,该方法会改变遵循该协议的类型的实例,就需要在方法前加 mutating 关键字。
2、实现协议中的 mutating 方法时,若是类类型,则不用写 mutating 关键字。而对于结构体和枚举,则必须写 mutating 关键字。
如:
protocol Togglable {
mutating func toggle()
}
如果使用枚举或结构体来实现 Togglable 协议时,需要提供一个带有 mutating 前缀的 toggle() 方法,如果是类实现 Togglable 协议则不用。
协议的构造器要求:
1、协议可以要求遵循协议的类型实现指定的构造器
protocol SomeProtocol {
init(someParameter: Int)
}
2、可以在遵循协议的类中实现构造器,无论是指定构造器,还是便利构造器都必须为构造器添加 required 修饰符。
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 这里是构造器的实现部分
}
}
3、如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符,因为 final 类不能有子类。
4、如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 required 和 override 修饰符:
class SomeSubClass: SomeSuperClass, SomeProtocol {
// 因为遵循协议,需要加上 required
// 因为继承自父类,需要加上 override
required override init() {
// 这里是构造器的实现部分
}
}
协议作为类型:
尽管协议本身并未实现任何功能,但是协议可以被当做一个功能完备的类型来使用。
委托:
定义协议来封装那些需要被委托的功能,这样就能确保遵循协议的类型能提供这些功能。
在扩展里添加协议遵循:
扩展可以为已有类型添加属性、方法、下标以及构造器。即便无法修改源代码,依然可以通过扩展令已有类型遵循并符合协议。
有条件地遵循协议:
可以通过在扩展类型时列出限制让泛型类型有条件地遵循某协议。在你采纳协议的名字后面写泛型 where 分句。
如:下面的扩展让 Array 类型只要在存储遵循 TextRepresentable 协议的元素时就遵循 TextRepresentable 协议。
extension Array: TextRepresentable where Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// 打印 "[A 6-sided dice, A 12-sided dice]"
在扩展里声明采纳协议:
当一个类型已经遵循了某个协议中的所有要求,却还没有声明采纳该协议时,可以通过空的扩展来让它采纳该协议。
使用合成实现来采纳协议:
Swift 可以自动提供一些简单场景下遵循 Equatable、Hashable 和 Comparable 协议的实现。在使用这些合成实现之后,无需再编写重复的代码来实现这些协议所要求的方法。
Swift 为以下几种自定义类型提供了 Equatable 协议的合成实现:
1、遵循 Equatable 协议且只有存储属性的结构体。
2、遵循 Equatable 协议且只有关联类型的枚举
3、没有任何关联类型的枚举
Swift 为以下几种自定义类型提供了 Hashable 协议的合成实现:
1、遵循 Hashable 协议且只有存储属性的结构体。
2、遵循 Hashable 协议且只有关联类型的枚举
3、没有任何关联类型的枚举
Swift 为没有原始值的枚举类型提供了 Comparable 协议的合成实现。
协议的继承:
协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求。
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 这里是协议的定义部分
}
类专属的协议:
通过添加 AnyObject 关键字到协议的继承列表,就可以限制协议只能被类类型采纳。
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// 这里是类专属协议的定义部分
}
协议合成:
1、要求一个类型同时遵循多个协议是很有用的。你可以使用协议组合来复合多个协议到一个要求里。协议组合不定义任何新的协议类型。
2、协议组合使用 SomeProtocol & AnotherProtocol 的形式
下面的例子中,将 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(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// 打印 “Happy birthday Malcolm - you're 21!”
检查协议一致性:is 和 as
1、is 用来检查实例是否遵循某个协议,若遵循则返回 true,否则返回 false;
2、as? 返回一个可选值,当实例遵循某个协议时,返回类型为协议类型的可选值,否则返回 nil;
3、as! 将实例强制向下转换到某个协议类型,如果强转失败,将触发运行时错误。
可选的协议方法:optional
协议中使用 optional 关键字来定义可选方法或属性。可选方法或属性需要和 OC 打交道。协议和可选方法或属性都必须带上 @objc 属性。标记 @objc 特性的协议只能被继承自 OC 类或者 @objc 类遵循,其他类以及结构体和枚举均不能遵循这种协议。
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
严格来讲,CounterDataSource 协议中的方法和属性都是可选的,因此遵循协议的类可以不实现这些要求,尽管技术上允许这样做,不过最好不要这样写。
协议扩展:
1、协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的默认实现。
2、如果遵循协议的类型自己实现了协议的方法或属性,那么就不会使用默认实现了。
如:PrettyTextRepresentable 协议的扩展提供了默认实现
extension PrettyTextRepresentable {
var prettyTextualDescription: String {
return textualDescription
}
}
为协议扩展添加限制条件:
扩展协议时,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 where 子句来描述
例如,你可以扩展 Collection 协议,当集合中的元素遵循了 Equatable 协议的情况。
extension Collection where Element: Equatable {
func allEqual() -> Bool {
for element in self {
if element != self.first {
return false
}
}
return true
}
}
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
由于数组遵循 Collection 而且整数遵循 Equatable,所以 equalNumbers 和 differentNumbers 都可以使用 allEqual() 方法。
print(equalNumbers.allEqual()) // 打印 "true"
print(differentNumbers.allEqual()) // 打印 "false"
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)