Protocols - 完成 对可选协议的规定

This commit is contained in:
futantan
2015-07-09 10:20:51 +08:00
parent e3e52f6eaf
commit 8432bd90ad

View File

@ -718,15 +718,18 @@ for object in objects {
<a name="optional_protocol_requirements"></a>
## 对可选协议的规定
可选协议含有可选成员,其`遵循者`可以选择是否实现这些成员。在协议中使用`@optional`关键字作为前缀来定义可选成员。
协议可以含有可选成员,其`遵循者`可以选择是否实现这些成员。在协议中使用`optional`关键字作为前缀来定义可选成员。
可选协议在调用时使用`可选链`,详细内容在[Optional Chaning](7)章节中查看。
<!--TODO 链接-->
可选协议在调用时使用`可选链`,因为协议的遵循者可能没有实现可选内容,详细内容在[Optional Chaning](7)章节中查看。
`someOptionalMethod?(someArgument)`这样,你可以在可选方法名称后加上`?`来检查该方法是否被实现。`可选方法``可选属性`都会返回一个`可选值(optional value)`,当其不可访问时,`?`之后语句不会执行,并整体返回`nil`
`someOptionalMethod?(someArgument)`这样,你可以在可选方法名称后加上`?`来检查该方法是否被实现。可选方法可选属性都会返回一个`可选值(optional value)`,当其不可访问时,`?`之后语句不会执行,并整体返回`nil`
> 注意: 可选协议只能在含有`@objc`前缀的协议中生效。且`@objc`的协议只能被`类`遵循
> 注意
> 可选协议只能在含有`@objc`前缀的协议中生效。且`@objc`的协议只能被`类`遵循
> 这个前缀表示协议将暴露给Objective-C代码详情参见`Using Swift with Cocoa and Objective-C`。即使你不打算和Objective-C有什么交互如果你想要指明协议包含可选属性那么还是要加上`@obj`前缀
如下所示,`Counter`类使用含有两个可选成员的`CounterDataSource`协议类型的外部数据源来提供`增量值(increment amount)`
下面的例子定义了一个叫`Counter`的整数加法类,它使用外部的数据源来实现每次的增量。数据源是两个可选属性,在`CounterDataSource`协议中定义:
```swift
@objc protocol CounterDataSource {
@ -735,9 +738,10 @@ for object in objects {
}
```
`CounterDataSource`含有`incrementForCount``可选方法``fiexdIncrement``可选属性`,它们使用了不同的方法来从数据源中获取合适的增量值。
`CounterDataSource`含有`incrementForCount`可选方法和`fiexdIncrement`可选属性,它们使用了不同的方法来从数据源中获取合适的增量值。
> 注意: `CounterDataSource`中的属性和方法都是可选的,因此可以在类中声明但不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。
> 注意
> `CounterDataSource`中的属性和方法都是可选的,因此可以在类中声明都不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。
`Counter`类含有`CounterDataSource?`类型的可选属性`dataSource`,如下所示:
@ -755,25 +759,27 @@ for object in objects {
}
```
`count`属性用于存储当前的值`increment`方法用来为`count`值。
`Counter`使用`count`存储当前的值。该类同时定义了一个`increment`方法,每次调用该方法的时候,将会增加`count`值。
`increment`方法通过`可选链`,尝试从两种`可选成员`中获取`count`
`increment()`方法首先试图使用`incrementForCount(_:)`方法来得到每次的增量。`increment()`方法使用可选链来尝试调用`incrementForCount(_:)`,并将当前的`count`值作为参数传入
1. 由于`dataSource`可能为`nil`,因此在`dataSource`后边加上了`?`标记来表明只在`dataSource`非空时才去调用`incrementForCount`方法。
这里使用了两种可选链方法。由于`dataSource`可能为`nil`,因此在`dataSource`后边加上了`?`标记来表明只在`dataSource`非空时才去调用`incrementForCount`方法。即使`dataSource`存在,但是也无法保证其是否实现了`incrementForCount`方法,因此在`incrementForCount`方法后边也加有`?`标记。
2. 即使`dataSource`存在,但是也无法保证其是否实现了`incrementForCount`方法,因此在`incrementForCount`方法后边也加有`?`标记
调用`incrementForCount`方法在上述两种情形都有可能失败,所以返回值为*可选*`Int`类型。虽然在`CounterDataSource`中,`incrementForCount`被定义为一个非可选`Int`(non-optional),但是这里我们仍然需要返回*可选*`Int`类型。
在调用`incrementForCount`方法后,`Int``可选值`通过`可选绑定(optional binding)`自动拆包并赋值给常量`amount`
在调用`incrementForCount`方法后,`Int``可选值`通过`可选绑定(optional binding)`自动拆包并赋值给常量`amount`如果可选值确实包含一个数值,这表示`delegate`和方法都存在,之后便将`amount`加到`count`上,增加操作完成。
`incrementForCount`不能被调用时,尝试使用可选属性`fixedIncrement`来代替
如果没有从`incrementForCount(_:)`获取到值,可能是`dataSource`为nil或者它并没有实现`incrementForCount`方法——那么`increment()`方法将试图从数据源的`fixedIncrement`属性中获取增量。`fixedIncrement`也是一个可选型,所以在属性名的后面添加`?`来试图取回可选属性的值。和之前一样,返回值为可选型
`ThreeSource`实现了`CounterDataSource`协议,如下所示:
`ThreeSource`实现了`CounterDataSource`协议,它实现来可选属性`fixedIncrement`,每次返回值`3`:
class ThreeSource: CounterDataSource {
let fixedIncrement = 3
}
```swift
@objc class ThreeSource: CounterDataSource {
let fixedIncrement = 3
}
```
使用`ThreeSource`作为数据源开实例化一个`Counter`:
可以使用`ThreeSource`的实例作为`Counter`实例的数据源:
```swift
var counter = Counter()
@ -788,7 +794,9 @@ for _ in 1...4 {
// 12
```
`TowardsZeroSource`实现了`CounterDataSource`协议中的`incrementForCount`方法,如下所示:
上述代码新建了一个`Counter`实例;将它的数据源设置为`TreeSource`实例;调用`increment()`4次。和你预想的一样每次在调用的时候`count`的值增加3.
下面是一个更为复杂的数据源`TowardsZeroSource`它将使得最后的值变为0:
```swift
class TowardsZeroSource: CounterDataSource {
@ -804,7 +812,11 @@ func incrementForCount(count: Int) -> Int {
}
```
下边是执行的代码:
`TowardsZeroSource`实现了`CounterDataSource`协议中的`incrementForCount(_:)`方法,以`count`参数为依据,计算出每次的增量。如果`count`已经为0方法返回0这表示之后不会再有增量。
你可以配合使用`TowardsZeroSource`实例和`Counter`实例来从`-4`增加到`0`.一旦增加到`0`,数值便不会再有变动。
在下面的例子中,将从`-4`增加到`0`。一旦结果为`0`,便不在增加:
```swift
counter.count = -4