在 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
}
}
但是您可以通过扩展来执行此操作(尽管扩展不支持存储属性,但它们支持函数和计算属性 - 尽管可以解决存储属性问题(。
这背后的解释是什么?作为补充,如果我们将协议和 func 都标记为@objc
,因此使其无法用于结构/枚举(它们不是基于值的(optional func
才可实现的解释是什么?
编辑:在扩展示例中添加
@optional
指令是 Objective-C 指令,尚未转换为 Swift。这并不意味着你不能在 Swift 中使用它,而是你必须首先使用@objc
属性向 Objective-C 公开你的 Swift 代码。
请注意,公开给 Obj-C 只会使协议对 Swift 和 Obj-C 中的类型可用,这不包括例如 Structs,因为它们仅在 Swift 中可用!
为了回答您的第一个问题,协议在这里定义而不是实现:
协议定义了方法、属性和其他要求的蓝图 [...]
因此,实现应该由符合它的类/stuct/enum 提供:
然后,可以通过类、结构或枚举采用该协议,以提供这些需求的实际实现
这个定义也适用于我们在日常生活中使用的协议。以编写论文的协议为例:
论文协议将论文定义为具有以下非零变量的文档:
- 介绍
- 章
- 结论
引言、章节和结论包含的内容取决于实现它们的人(作者(而不是协议。
当我们查看扩展的定义时,我们可以看到它们在这里添加(实现(新功能:
扩展向现有类、结构、枚举或协议类型添加新功能。这包括扩展您无权访问其原始源代码的类型的功能。
因此,扩展协议(这是允许的(使您可以添加新功能,并在此提供已定义方法的默认实现。这样做将作为上面讨论的@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)