位置:首页 > 高级语言 > Swift在线教程 > Swift可选协议要求

Swift可选协议要求

可选协议要求

可选协议含有可选成员,其遵循者可以选择是否实现这些成员。在协议中使用@optional关键字作为前缀来定义可选成员。

可选协议在调用时使用可选链,详细内容在可选链章节中查看。

someOptionalMethod?(someArgument)一样,你可以在可选方法名称后加上?来检查该方法是否被实现。可选方法可选属性都会返回一个可选值(optional value),当其不可访问时,?之后语句不会执行,并返回nil


注意: 可选协议只能在含有@objc前缀的协议中生效。且@objc的协议只能被遵循。
 

Counter类使用CounterDataSource类型的外部数据源来提供增量值(increment amount),如下所示:

@objc protocol CounterDataSource {
    @optional func incrementForCount(count: Int) -> Int
    @optional var fixedIncrement: Int { get }
}

CounterDataSource含有incrementForCount可选方法fiexdIncrement可选属性


注意: CounterDataSource中的属性和方法都是可选的,因此可以在类中声明但不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。
 

Counter类含有CounterDataSource?类型的可选属性dataSource,如下所示:

@objc class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.incrementForCount?(count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement? {
            count += amount
        }
    }
}

count属性用于存储当前的值,increment方法用来为count赋值。

increment方法通过可选链,尝试从两种可选成员中获取count

  1. 由于dataSource可能为nil,因此在dataSource后边加上了?标记来表明只在dataSource非空时才去调用incrementForCount`方法。
  2. 即使dataSource存在,但是也无法保证其是否实现了incrementForCount方法,因此在incrementForCount方法后边也加有?标记。

在调用incrementForCount方法后,Int可选值通过可选绑定(optional binding)自动拆包并赋值给常量amount

incrementForCount不能被调用时,尝试使用可选属性``fixedIncrement来代替。

ThreeSource实现了CounterDataSource协议,如下所示:

class ThreeSource: CounterDataSource {
    let fixedIncrement = 3
}

使用ThreeSource作为数据源开实例化一个Counter

var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    println(counter.count)
}
// 3
// 6
// 9
// 12

TowardsZeroSource实现了CounterDataSource协议中的incrementForCount方法,如下所示:

class TowardsZeroSource: CounterDataSource {
func incrementForCount(count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}

下边是执行的代码:

counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
    counter.increment()
    println(counter.count)
}
// -3
// -2
// -1
// 0
// 0