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. 实践001:char 类型字段在表中的长度

    Rainy on 20170215 1.同事在 写RFC的时候遇到报错:"YTST_001" 必须为扁平结构.不能将内部表.字符# 原因是自建结构中字段定义为了string 类型. ...

  2. eclipse 重启/打开内置浏览器

    重启 Eclipse 重启选项允许用户重启 Eclipse. 我们可以通过点击 File 菜单选择 Restart 菜单项来重启 Eclipse. Eclipse 内置浏览器 Web 浏览器 Ecli ...

  3. HTTP协议 (一) HTTP协议详解

    当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为它让我们理解了We ...

  4. touch all contents in a folder recursively

    https://superuser.com/questions/598163/powershell-touch-all-files-newer-than Powershell to use Unix ...

  5. NSArray, NSSet, NSDictionary

    一.Foundation framework中用于收集cocoa对象(NSObject对象)的三种集合分别是: NSArray 用于对象有序集合(数组)NSSet 用于对象无序集合(集合) NSDic ...

  6. [SCOI 2007] 修车

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1070 [算法] 首先 , 我们发现 , 在倒数第i个修车会对答案产生i * k的贡献 ...

  7. bzoj2002 [Hnoi2010]Bounce 弹飞绵羊——分块

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 第一次用分块,感觉超方便啊: 如果记录每个点的弹力系数,那么是O(1)修改O(n)查询 ...

  8. python标准输入,标准输出,标准错误

    sys.stdout 与 print 当我们在 Python 中打印对象调用 print obj 时候,事实上是调用了 sys.stdout.write(obj+'\n') print 将你需要的内容 ...

  9. c++性能测试工具:google benchmark入门(二)

    上一篇中我们初步体验了google benchmark的使用,在本文中我们将更进一步深入了解google benchmark的常用方法. 本文索引 向测试用例传递参数 简化多个类似测试用例的生成 使用 ...

  10. 关于XAMPP Apache无法启动问题解决方案

    安装好XAMPP后,启动Apache服务启动失败,然后从xampp安装目录下执行apache_start.bat文件,如下图 显示443端口被占用. 解决方法: 启动cmd,输入netstat -a  ...