gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 06:13:56 35 4
gpt4 key购买 nike

在 Swift 中,您不能在协议(protocol)定义本身中定义函数或属性的默认实现,即:

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
}
}

但是您可以通过扩展来实现(尽管扩展不支持存储属性,但它们支持函数和计算的属性 - 尽管存储属性问题可能是 worked around)。

这背后的解释是什么?作为补充,如果我们将协议(protocol)和函数都标记为 @objc 并因此使其无法用于 Structs/Enums,那么 optional func 只能实现的解释是什么(哪些值不是基于引用的)?

编辑:在扩展示例中添加

最佳答案

@optional 指令是一个仅用于 Objective-C 的指令,尚未转换为 Swift。这并不意味着您不能在 Swift 中使用它,而是您必须首先使用 @objc 属性将 Swift 代码公开给 Objective-C。

请注意,暴露给 Obj-C 只会使协议(protocol)可用于 Swift 和 Obj-C 中的类型,这不包括例如结构,因为它们仅在 Swift 中可用!

要回答您的第一个问题,协议(protocol)是用来定义而不是实现的:

A protocol defines a blueprint of methods, properties, and other requirements [...]

因此,实现应该由符合它的类/结构/枚举提供:

The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements

这个定义确实适用于我们在日常生活中使用的协议(protocol)。以写一篇论文的协议(protocol)为例:

PaperProtocol 将论文定义为具有以下非零变量的文档:

  • 简介
  • 章节
  • 结论

引言、章节和结论包含的内容取决于实现它们的人(作者),而不是协议(protocol)。

当我们查看 Extensions 的定义时,我们可以看到它们在这里添加(实现)新功能:

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code.

因此,扩展协议(protocol)(这是允许的)使您有可能添加新功能,并因此提供已定义方法的默认实现。这样做将作为上述 @optional 指令的 Swift 唯一替代方案。

更新:

虽然在 Switch 中为协议(protocol)函数提供默认实现确实使其成为“可选”,但它与在 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)

关于swift - 为什么协议(protocol)默认值必须通过 Swift 中的扩展来实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45671631/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com