资源推荐:
- Protocol-Oriented Programming in Swift: WWDC 2015 session
- The Best of What’s New in Swift
- Protocol Oriented Programming in the Real World
- Locksmith : A powerful, protocol-oriented library for working with the keychain in Swift.
- Blurable : Apply a Gaussian Blur to any UIView with Swift Protocol Extensions.
此文为 The Best of What’s New in Swift 有关Protocol Extensions的翻译。
Protocol Extensions
在Swift 2.0 之前, Objective-C和Swift,在protocols中只能包含方法声明。 protocols只包含接口定义即一堆等待遵守类型去实现的方法。 在Swift 2中使用 protocol extensions, protocols可以既包含声明,也可以包含实现。
经常,会有很多功能性方法适用于一类对象。 如, 所有的集合类型都可以有将一个集合内对象经过映射(map),而创建一个映射后的集合对象。 在Swift 2之前, 有两种方式可以达到这种能力。
* 在protocol中声明方法并要求对应遵循接口的对象实现自己的方法
* 全局函数
Cocoa基本上采用的是第一种解决方案。 虽然这些方法可能太适合成为任何protocol的一部分, 但是Cocoa的集合对象都有一个enumerateObjectsUsingBlock:方法,每个集合类型有各自的实现。
Swift 2之前,采用的是第二种解决方案。 想 map 这种全局函数,操作于 CollectionType . 这种方式很好的共享了函数实现, 但是语法奇怪并且不能针对特定类型重写实现方法。
有了 protocol extensions , 我们可以有了更牛X的第三种方式。 map 可以实现在 CollectionType 的一个扩展(extension)中。 所有遵循 CollectionType 的类型,就自动获得了一个 map 实现。
一下为一个简单的 map 函数实现:
1 | extension CollectionType { |
之前只可以作为 Array 的扩展,然后只可以在 Array 中使用。 有了一个接口的扩展, 上面的实现也可以在 Set 和 ArraySlice 和其他遵循 CollectionType 接口的类型中获得。
另一个很有意思的Swift protocol extensions特性是可以对类型做出限制。 举个栗子, 如果你想实现一个 max 属性。 但是 max 并不适用于所有集合类型, 只有那些有序集合才使用这个属性。 没问题! 只要给扩展加一个限制,要求其实现类型必须遵守 Comparable 协议:
1 | extension CollectionType where Self.Generator.Element: Comparable { |
protocol extensions 有一个会令人迷惑的地方, 虽然很小但是很重要,决定了protocol extension中方法是否需要动态分发(dynamic dispatch)。
一个在protocol extension中声明的方法也许也会在protocol中声明, 或者只存在于extension中。 只存在extension中的方法,不会动态分发(dynamic dispatch)并且也不能被复写。只声明在protocol中的方法是动态分发(dynamic dispatch)的并且可以被复写。talk is cheap, show me the code:
1 | protocol P { |
上面的代码会打印出:1
specialized implementation of A和default implementation of B.
使用protocol extensions还可以让Swift的protocol方法成为“可选”方法,在Swift 2中,我们可以这样实现一个delegate中的可选方法:
1 |
|