如何为Objective-C可选协议方法提供默认实现?
实施例
extension AVSpeechSynthesizerDelegate {
func speechSynthesizer(synthesizer: AVSpeechSynthesizer, didFinishSpeechUtterance utterance: AVSpeechUtterance) {
print(">>> did finish")
}
}
期望:无论何时符合AVSpeechSynthesizerDelegate
的类都应该在语音完成时运行上述函数。
答案 0 :(得分:3)
你完全按照你的实施方式去做。差异最终在于如何实际调用该方法。
让我们以非常简化示例:
@objc protocol FooProtocol {
optional func bar() -> Int
}
class Omitted: NSObject, FooProtocol {}
class Implemented: NSObject, FooProtocol {
func bar() -> Int {
print("did custom bar")
return 1
}
}
通过不添加其他代码,我希望必须使用此代码:
let o: FooProtocol = Omitted()
let oN = o.bar?()
let i: FooProtocol = Implemented()
let iN = i.bar?()
oN
和iN
最终都有Int?
类型,oN
为nil
,iN
为1
且我们看到文字"did custom bar"
打印。
重要的是,不是可选链接的方法调用:bar?()
,括号中方法名称之间的问号。这就是我们必须从Swift调用可选协议方法的方法。
现在让我们为我们的协议添加扩展名:
extension FooProtocol {
func bar() -> Int {
print("did bar")
return 0
}
}
如果我们坚持原始代码,我们可选择链接方法调用,行为没有变化:
然而,通过协议扩展,我们不再需要选择性地解包。我们可以选择展开,扩展名称为:
这里不幸的问题是,这不一定特别有用,是吗?现在我们每次只调用扩展中实现的方法。
所以如果你可以控制使用协议和调用方法的类,那么选择就会更好一些。您可以检查班级是否响应选择器:
let i: FooProtocol = Implemented()
if i.respondsToSelector("bar") {
i.bar?()
}
else {
i.bar()
}
这也意味着您必须修改协议声明:
@objc protocol FooProtocol: NSObjectProtocol
添加NSObjectProtocol
可以让我们拨打respondsToSelector
,并且根本不会改变我们的协议。我们必须继承NSObject
才能实施标记为@objc
的协议。
当然,尽管如此,任何Objective-C代码都无法在Swift类型上执行此逻辑,并且可能无法实际调用这些协议中实现的方法似乎是扩展。因此,如果您试图从Apple的框架中获取某些内容来调用扩展方法,那么您似乎运气不好。似乎即使你试图在Swift中调用其中一个,如果它的协议方法标记为optional
,那么这不是一个非常好的解决方案。