Swift protocol extension method is called instead of method implemented in subclass

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

This is just how protocols currently dispatch methods.

A protocol witness table (see this WWDC talk for more info) is used in order to dynamically dispatch to implementations of protocol requirements upon being called on a protocol-typed instance. All it is, is really just a listing of the function implementations to call for each requirement of the protocol for a given conforming type.

Each type that states its conformance to a protocol gets its own protocol witness table. You'll note that I said "states its conformance", and not just "conforms to". BaseClass gets its own protocol witness table for conformance to MyProtocol. However SubClass does not get its own table for conformance to MyProtocol – instead, it simply relies on BaseClass's. If you moved the

: MyProtocol down to the definition of SubClass, it would get to have its own PWT.

So all we have to think about here is what the PWT for BaseClass looks like. Well, it doesn't provide an implementation for either of the protocol requirements methodA() or methodB() – so it relies on the implementations in the protocol extension. What this means is that the PWT for BaseClass conforming to MyProtocol just contains mappings to the extension methods.

So, when the extension methodB() method is called, and makes the call out to methodA(), it dynamically dispatches that call through the PWT (as it's being called on a protocol-typed instance; namely self). So when this happens with a SubClass instance, we're going through BaseClass's PWT. So we end up calling the extension implementation of methodA(), regardless of the fact that SubClass provides an implementation of it.

Now let's consider the PWT of JustClass. It provides an implementation of methodA(), therefore its PWT for conformance to MyProtocol has that implementation as the mapping for methodA(), as well as the extension implementation for methodB(). So when methodA() is dynamically dispatched via its PWT, we end up in its implementation.

As I say in this Q&A, this behaviour of subclasses not getting their own PWTs for protocols that their superclass(es) conform to is indeed somewhat surprising, and has been filed as a bug. The reasoning behind it, as Swift team member Jordan Rose says in the comments of the bug report, is

Therefore if this was the behaviour, already-compiled subclasses would lack any PWTs from superclass conformances that were added after the fact in another module, which would be problematic.

As others have already said, one solution in this case is to have BaseClass provide its own implementation of methodA(). This method will now be in BaseClass's PWT, rather than the extension method.

Although of course, because we're dealing with classes here, it won't just be BaseClass's implementation of the method that's listed – instead it will be a thunk that then dynamically dispatches through the class' vtable (the mechanism by which classes achieve polymorphism). Therefore for a SubClass instance, we'll wind up calling its override of methodA().

https://stackoverflow.com/questions/44703205/swift-protocol-extension-method-is-called-instead-of-method-implemented-in-subcl

Swift protocol extension method is called instead of method implemented in subclass的更多相关文章

  1. Swift 使用Extension 场景 浅析

    别人一看到我的 Swift 代码,立刻就会问我为什么如此频繁的使用 extension.这是前几天在我写的另一篇文章中收到的评论: 我大量使用 extension 的主要目的是为了提高代码可读性.以下 ...

  2. swift protocol 与类继承结合时的bug

    protocol CommonTrait: class { func commonBehavior() -> String } extension CommonTrait { func comm ...

  3. (细节控)swift3.0与融云IMKIT开发问题(一部分) override func onSelectedTableRow Method does not override any method from its superclass

    原官网文档方案如下,在swift3.0的情况下出现 override func onSelectedTableRow  Method does not override any method from ...

  4. org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method test() on null context object

    前言 本文中提到的解决方案,源码地址在:springboot-thymeleaf,希望可以帮你解决问题. 至于为什么已经写了一篇文章thymeleaf模板引擎调用java类中的方法,又多此一举的单独整 ...

  5. 【iOS】Swift扩展extension和协议protocol

    加上几个关节前Playground摘要码进入github在,凝视写了非常多,主要是为了方便自己的未来可以Fanfankan. Swift语法的主要部分几乎相同的. 当然也有通用的.运算符重载.ARC. ...

  6. swift protocol 见证容器 虚函数表 与 动态派发

    一.测试代码: //protocol DiceGameDelegate: AnyObject { //} // //@objc protocol OcProtocol{ //    @objc fun ...

  7. swift protocol的几种形式

    三个关注点:1.形式:2.实现方式:3.使用方式: 一.基本形式: 形式:内部无泛型类型: 实现:只需指定类型和实现相应的功能即可: 使用:可以用在其他类型出现的任何地方: protocol Resp ...

  8. Swift 扩展(Extension)总结

    概要 扩展是给已经存在的类(class),结构体(structure),枚举类型(enumeration)和协议(protocol)增加新的功能.类似Objective-C中的Category,不同的 ...

  9. swift class extension 与继承

    1.扩展中无法继承重写已有函数,不能添加函数. Extensions can add new functionality to a type, but they cannot override exi ...

随机推荐

  1. GrideView(二)---删除功能

    情景一. 没有外键关联, 操作:在数据源中将删除选项选中--- GrideView 中的删除 选项选中 即可情景二. 有外键关联 *RowDeleting 行删除前触发 *RowDeleted 行删除 ...

  2. YTU 2845: 编程题AB-卡片游戏

    2845: 编程题AB-卡片游戏 时间限制: 1 Sec  内存限制: 128 MB 提交: 30  解决: 13 题目描述 小明对数字的序列产生了兴趣: 现有许多张不同的数字卡片,用这若干张卡片能排 ...

  3. YTU 2915: Shape系列-1

    2915: Shape系列-1 时间限制: 1 Sec  内存限制: 128 MB 提交: 283  解决: 221 题目描述 小强开始迷恋彩色的Shape,于是决定做一个Shape类.Shape类有 ...

  4. HTML与JSP页面的区别

    HTML(Hypertext Markup Language)文本标记语言,它是静态页面,和JavaScript一样解释性语言,为什么说是解释性 语言呢?因为,只要你有一个浏览器那么它就可以正常显示出 ...

  5. bzoj 1941 Hide and Seek

    题目大意: n个点,求每个点到其最远点距离-到其最近点距离(除自己之外)的最小值 思路: 对于估计函数的理解还不够深刻 #include<iostream> #include<cst ...

  6. bzoj 3714 [ PA 2014 ] Kuglarz —— 思路+最小生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3714 因为每个杯子下最多一个小球,所以从奇偶性就可以看出有没有球: 询问一段区间,等于知道一 ...

  7. Git 仓库结构 (二)***

    一.GIT工作流程 了解git,首先要弄清楚对象在被git管理过程中所处的4个阶段,分别是: 工作目录 index(又称为暂存区) 本地仓库 远程仓库. 从时间先后来讲,工作目录的内容是你当前看到的, ...

  8. 如何替换某文件中的所有的特定字符?---linux sed命令(文本编辑命令) (转载)

    转自:http://blog.csdn.net/year_9/article/details/20318407 sed是一个很好的文件处理工具,主要是以行为单位进行处理,可以将数据行进行替换.删除.新 ...

  9. 查询及删除重复记录的SQL语句

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select * from people where peopleId in (select peopleId from ...

  10. 【WIP】Swift4 异常处理, JSON处理

    创建: 2018/03/24 更新: 2018/06/05 补充catch可以只带where不带模式 [任务表]TODO 异常处理语法  异常的发生 抛出例外 thorw 式 ● 抛出的值的类型必须采 ...