阅读 423
【Swift-被忽视的角落】Protocol方法的静态派发与动态派发

【Swift-被忽视的角落】Protocol方法的静态派发与动态派发

Hi 👋

My apps

-扫雷Elic 无尽天梯梦见账本
类型游戏财务
AppStoreElicUmemi

一、 场景一

我们定义这样一个Protocol

protocol DescriptionProtocol {
    var name: String { get }
}
复制代码

添加拓展方法 printDescription

extension DescriptionProtocol {
    func printDescription() {
        print("我是:\(name)")
    }
}
复制代码

新建类 Apple 遵循协议 DescriptionProtocol

class Apple: DescriptionProtocol {
    var name: String {
        return "苹果"
    }
    
    func printDescription() {
        print("\(name)好好吃啊!")
    }
}
复制代码

新建类 People 遵循协议 DescriptionProtocol

class People: DescriptionProtocol {
    var name: String {
        return "人类"
    }
    
    func printDescription() {
        print("\(name)真有意思!")
    }
}
复制代码

分别创建实例对象

let aApple = Apple()
let aPeople = People()

aApple.printDescription()
aPeople.printDescription()
复制代码

1.1 思考

🤔思考一下会输出什么呢?














// 这里是调用了Class内实现的方法,而没有调用protocol的拓展实现
aApple.printDescription() // 苹果好好吃啊!
aPeople.printDescription() // 人类真有意思!
复制代码

1.2 换一种方式调用

func showDescription(of: DescriptionProtocol) {
    of.printDescription()
}

showDescription(of: aApple)
showDescription(of: aPeople)
复制代码
🤔思考一下会输出什么呢?
















showDescription(of: aApple) // 我是:苹果
showDescription(of: aPeople) // 我是:人类
复制代码

1.3 是不是感觉很奇怪?

  • aApple.printDescription()
    • 这种方式直接调用了类定义的实例方法,而不是协议中实现的方法,是动态派发的
  • showDescription
    • 中调用的是Protocol中实现的函数,是静态派发
  • printDescription在协议中和类中虽然同名,但却是毫不相干的函数,存储的区域也各不相同

二、 场景二

我们将函数在协议中声明一下下,又会有什么结果呢?

protocol DescriptionProtocol {
    var name: String { get }
    func printDescription()
}
复制代码

结果:

苹果好好吃啊!
人类真有意思!
苹果好好吃啊!
人类真有意思!
复制代码
  • aApple.printDescription()
    • 和场景一是一样的,是动态派发
  • showDescription
    • 调用了协议中声明的函数,是动态派发

三、 总结

由继承而得到的多态表现,本质上是把所有的方法的实现都放在一张里,每次调用都必须先在表中查询,可以称之为动态派发。 因此才有了覆写的概念:方法被覆写,即当子类调用该方法时,会使用子类的实现而非父类的。

而协议与类有所不同。协议所定义的方法,也和类一样,是动态派发的;但那些未出现在定义中,而仅出现于 Extension 中的方法是静态派发的,即这个方法属于协议,不属于协议的遵从者。

性能上也是静态优于动态。像是一些高频调用的函数我们可以通过静态的方式来做提高效率。动态派发虽然步骤会多一些,比如OC的消息转发机制,但是充满灵活性,在业务开发中会经常用到。

这里只是在表面上进行了探索,还未从源码角度分析。等有时间从源码角度再分析一次

参考

static-vs-dynamic-dispatch-in-swift

文章分类
iOS
文章标签