在Swift中,您无法在协议定义本身中定义函数或属性的默认实现,即:
protocol Container {
//These are fine
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get set }
subscript(i: Int) -> Item { get }
//These are not fine
var defaultValue: Int = 10
mutating func messWithCount(){
self.count *= 10
}
}
extension Container {
//This is fine though
mutating func messWithCount(){
self.count *= 10
}
}
但你可以通过扩展来实现(虽然Extensions不支持存储属性,它们支持函数和计算属性 - 尽管存储的属性问题可以是worked around)。
这背后的解释是什么?作为补充,如果我们将Protocol和func都标记为optional func
并因此使其无法用于Structs / Enums(基于Value not Reference),那么@objc
只能实现的解释是什么? ?
编辑:在扩展示例中添加
答案 0 :(得分:1)
@optional
指令是一个仅限Objective-C的指令,尚未转换为Swift。这并不意味着您不能在Swift中使用它,而是必须首先使用@objc
属性将Swift代码暴露给Objective-C。
请注意,暴露给Obj-C只会使协议可用于Swift和Obj-C中的类型,这不包括例如Structs,因为它们仅在Swift中可用!
要回答您的第一个问题,协议就在这里定义而不是实现:
协议定义了方法,属性和其他要求的蓝图[...]
因此,实现应该由符合它的类/ stuct / enum提供:
然后可以通过类,结构或枚举来采用该协议,以提供这些要求的实际实现
这个定义确实适用于我们日常生活中使用的协议。以编写论文的协议为例:
PaperProtocol 将论文定义为具有以下非零变量的文档:
引言,章节和结论包含的内容取决于实现它们的人(作者)而不是协议。
当我们查看扩展的定义时,我们可以看到他们在这里添加(实现)新功能:
扩展为现有的类,结构,枚举或协议类型添加新功能。这包括扩展您无权访问原始源代码的类型的能力。
因此扩展协议(允许)可以添加新功能,从而提供已定义方法的默认实现。这样做将作为Swift唯一替代上面讨论的@optional
指令。
更新:
虽然为Switch中的协议函数提供默认实现确实使其“可选”,但它与在Objective-C中使用@optional
指令基本上不同。
在Objective-C中,一个未实现的可选方法根本没有实现,因此调用它会导致崩溃,因为它不存在。因此,在调用它之前必须检查它是否存在,与Swift相反,使用扩展名默认值,您可以安全地调用它作为默认实现。
Obj-C中的可选项将如下使用:
NSString *thisSegmentTitle;
// Verify that the optional method has been implemented
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
// Call it
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
} else {
// Do something as fallback
}
其中Swift对应的扩展名默认为:
let thisSegmentTitle = self.dataSource.titleForSegmentAtIndex(index)