当前位置: 首页 > 面试题库 >

调用Swift协议扩展方法代替在子类中实现的方法

洪俊捷
2023-03-14
问题内容

我遇到了以下代码(Swift 3.1)中解释的问题:

protocol MyProtocol {
    func methodA()
    func methodB()
}

extension MyProtocol {
    func methodA() {
        print("Default methodA")
    }

    func methodB() {
        methodA()
    }
}

// Test 1
class BaseClass: MyProtocol {

}

class SubClass: BaseClass {
    func methodA() {
        print("SubClass methodA")
    }
}


let object1 = SubClass()
object1.methodB()
//

// Test 2
class JustClass: MyProtocol {
    func methodA() {
        print("JustClass methodA")
    }
}

let object2 = JustClass()
object2.methodB()
//
// Output
// Default methodA
// JustClass methodA

因此,我希望在调用后应打印 _“ SubClassmethodA”_文本object1.methodB()。但是由于某种原因,methodA()调用了from协议扩展的默认实现。但是,object2.methodB()呼叫按预期方式工作。

是协议方法调度中的另一个Swift错误,还是我丢失了一些东西并且代码正常工作?


问题答案:

这就是协议当前调度方法的方式。

协议见证表(有关更多信息,请参见WWDC谈话)用于在协议类型的实例上被调用时动态地调度到协议要求的实现。实际上,这只是功能实现的清单,以针对给定的符合类型调用协议的每种要求。

声明其对协议一致性的每种类型都有其自己的协议见证表。您会注意到,我说的是“说明其一致性”,而不仅仅是“符合”。BaseClass获得自己的协议见证表以符合要求MyProtocol。但是,SubClass
没有 获得自己的表来符合MyProtocol–相反,它仅依赖于BaseClass。如果将
: MyProtocol下移到的定义SubClass,它将具有自己的PWT。

因此,我们仅需考虑的是PWT的BaseClass外观。那么,它不会为任何的协议要求提供一个实现methodA()methodB()-因此它依赖于该协议扩展的实现。这意味着BaseClass符合的PWT
MyProtocol仅包含到扩展方法的映射。

因此,当methodB()调用extension
方法并将其发出到时methodA(),它会通过PWT动态分派该调用(因为它是在协议类型的实例上调用,即self)。因此,当SubClass实例发生这种情况时,我们将进行BaseClassPWT。因此methodA(),无论是否SubClass提供扩展实现,我们最终都会调用的扩展实现。

现在让我们考虑的PWT JustClass。它提供的实现methodA(),因此,其对符合PWT MyProtocol具有
实施作为映射methodA(),以及对于扩展实现methodB()。因此,当methodA()通过其PWT动态调度时,我们最终实现了

正如我在本问答中所提到的,子类的这种行为没有为其超类所遵循的协议获取自己的PWT确实有些令人惊讶,并且已被记录为bug。正如Swift团队成员Jordan
Rose在错误报告的评论中所说的那样,其背后的原因是

[…]子类无法提供新成员来满足一致性要求。这很重要,因为可以将协议添加到一个模块中的基类,而可以将其添加到另一个模块中。

因此,如果这是行为,那么已经编译的子类将缺少事实之后在另一个模块中添加的超类一致性中的任何PWT,这将是有问题的。

正如其他人已经说过的,这种情况下的一种解决方案是BaseClass提供自己的实现methodA()。现在,此方法将位于BaseClass的PWT中,而不是扩展方法中。

尽管当然,因为我们在这里处理 ,所以它不只是BaseClass‘列出方法的实现-
而是一个笨拙的东西,然后通过该类动态分配vtable(类实现该机制的机制多态性)。因此,对于一个SubClass实例,我们最终将调用其的覆盖methodA()



 类似资料:
  • 问题内容: 我发现了一个有趣的行为,似乎是一个错误… 基于行为描述了以下文章: https://medium.com/ios-os-x-development/swift-protocol-extension-method- dispatch-6a6bf270ba94 http://nomothetis.svbtle.com/the-ghost-of-swift-bugs- future 当添加时

  • 问题内容: 使用默认实现的Swift 2协议扩展遇到了一个问题。基本要点是,我已经提供了协议方法的默认实现,我将在实现该协议的类中重写该方法。该协议扩展方法是从基类中调用的,然后该基类将调用在派生类中已重写的方法。结果是未调用重写的方法。 我试图将问题提炼到最小的游乐场,以说明以下问题。 问题答案: 不幸的是,协议还没有这样的动态行为。 但是,您可以(在类的帮助下)通过在中实现并在中进行覆盖来做到

  • 问题内容: 我有以下类层次结构: 实现一种协议方法,例如 在继承自的类中,不再调用新的可选协议方法,例如 问题答案: tl; dr,您需要在函数声明之前添加其Objective-C声明,例如 借助《Swift 3迁移指南》,我被告知这是一个解决方案,其中指出: 如果在声明符合性的类的子类中实现可选的Objective-C协议要求,则会看到警告,“实例方法’…’几乎与协议’…’的可选要求’…’相匹配

  • 问题内容: 我正在尝试使用Swift协议扩展,却发现这种行为令人困惑。您能帮我得到我想要的结果吗? 请参阅代码最后4行的注释。(如果需要,可以将其复制粘贴到Xcode7游乐场)。谢谢!! 问题答案: 简短的答案是协议扩展不执行类多态性。这是有一定道理的,因为协议可以被结构或枚举采用,并且因为我们不希望仅在没有必要的地方采用协议来引入动态调度。 因此,在中,实例变量(可能更准确地写为)并不意味着您认

  • 问题内容: 我想知道是否有可能实现这样的目标。 我有一个这样的游乐场: 我可以在中提供默认实现,但是如果需要默认实现中的所有内容以及其他内容,该怎么办? 它在某种程度上类似于es中的调用方法,可以满足实现每个属性等的要求。但是我看不到用实现相同的可能性。 问题答案: 我不知道您是否还在寻找答案,但是要做的方法是从协议定义中删除函数,将对象转换为对象,然后在其上调用方法: 由于某种原因,它仅在函数未

  • 本文向大家介绍C#中子类调用父类的实现方法,包括了C#中子类调用父类的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#中实现子类调用父类的方法,分享给大家供大家参考之用。具体方法如下: 一、通过子类无参构造函数创建子类实例 创建父类Person和子类Student。 在客户端通过子类无参构造函数创建子类实例。 输出结果: 可见:通过调用子类无参构造函数创建子类实例,会默认调用父