为什么协议默认值必须通过 Swift 中的扩展来实现?



在 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)

最新更新