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. ibatis和mybatis的区别

    区别1:全局配置文件(sqlMapConfig.xml)的差异 主要是元素标签命名的差异,比如mybatis的根元素标签为<configuration>,ibatis的 根元素标签为< ...

  2. android编译openssl静态库.a

    github上有一个开源项目,已经为你编译openssl建好了工程. 地址:https://github.com/aluvalasuman/OpenSSL1.0.1cForAndroid 选择需要的版 ...

  3. silverlight DataGrid 显示篇

    silverlight DataGrid 显示篇 分类: Silverlight2012-05-12 21:55 693人阅读 评论(0) 收藏 举报 datagridsilverlightbindi ...

  4. jfreechart应用2--柱状图(作者:百度 被风吹过的日子)

    jfreechart应用2--柱状图 二.   柱状图 在WebRoot目录下建立bar目录,用来存放柱状图的各个例子.首先在该目录下建立一个sample1.jsp文件,让我们来看一个简单的柱状图的例 ...

  5. mysql数据恢复失败记录

    今天遇到了MySQL有几个数据表空间丢失的问题,作为一个外行尝试好久没恢复成功,考虑到只是几个基础数据表,就删除数据表停止服务,删除ibd文件后再创新创建表解决了问题. 近期的一些事让我不像以前一样钻 ...

  6. 循环冗余检验 (CRC) 算法原理

    Cyclic Redundancy Check循环冗余检验,是基于数据计算一组效验码,用于核对数据传输过程中是否被更改或传输错误. 算法原理 假设数据传输过程中需要发送15位的二进制信息g=10100 ...

  7. FB 对话框接口

    官方文档: https://developers.facebook.com/docs/dialogs FB的对话框主要是调用 FB.ui(); 方法. 有问题上官网看文档是最好的. 1. send D ...

  8. Gym 100512F Funny Game (博弈+数论)

    题意:给两个数 n,m,让你把它们分成 全是1,每次操作只能分成几份相等的,求哪一个分的次数最多. 析:很明显,每次都除以最小的约数是最优的. 代码如下: #pragma comment(linker ...

  9. 搭建CARDBOARD+ANDROID+unity3d的VR开发环境

    一.下载最新unity3d(u3d官网) 二.下载最新cardboardsdkforunity(https://github.com/googlesamples/cardboard-unity) 三. ...

  10. Mac下Ruby升级与Rails的安装

    也是醉了,网上查了半天一脸懵逼.然后自己动手试试 gem install rails瞬间命令行就没反应了,以为命令行挂了,但是一会儿报错说是没有权限. 好吧,那么来这个 sudo gem instal ...