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

时间:2017-08-14 09:39:39

标签: swift reference protocols extension-methods

在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只能实现的解释是什么? ?

编辑:在扩展示例中添加

1 个答案:

答案 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)