Swift中的函数派发机制

函数派发机制指的是程序如何找到函数并执行操作的机制。各种各样不同的需求导致不同的函数派发机制。有时可能希望函数直接执行,比如C++的默认派发机制,有时可能需要函数在运行时执行,那就需要通过函数表派发,比如java,或者需要通过消息派发,比如Objc。但是每种派发机制都有优缺点。

常见的函数派发

静态派发

静态派发也叫直接派发。在静态派发中,编译器直接找到相关指令的位置。当函数调用时,系统直接跳转到函数的内存地址执行操作。这样的好处就是执行快,同时允许编译器能够执行例如内联等优化。事实上,编译期在编译阶段为了能够获取最大的性能提升,都尽量将函数静态化。

动态派发

动态派发是一种运行时机制。在运行时决定函数的执行。这种机制产生的原因就是面向对象语言的多态性。原先的静态派发由于在编译时就决定了,所以灵活性就不够。

函数表派发

函数表派发就是通过函数表来查找相应的函数地址。每个类在创建时都会创建一个函数表,用来记录函数的指针。同时子类在创建时也会创建一个函数表,如果函数是override的,则使用一个新的指针,用于区分父类中相同函数的指针。如果这个函数是父类中有且没被override的,则存储的就是原先的指针。具体可以看下面的代码和图示。

class Animal {
    func eat() {}
    func drink() {}
}
class Bird: Animal {
    override func eat() {}
    func fly () {}
}

当执行Bird类中的eat函数时整个流程如下:
1.读取Bird类的函数表地址Oxb00。
2.读取到eat函数,也就是0xb00+1。
3.跳转到0x330执行具体的操作。

函数表

从上面的分析中我们可以知道,要具体执行fly函数,就必须进行两次读取和一次跳转。同时编译器对于函数表派发的函数是无法执行优化的。这样,执行速度必然就变慢了。

消息派发

Objc的函数派发都是基于消息派发的。这种机制极具动态性,既可以通过swizzling修改函数的实现,也可以通过isa-swizzling修改对象。
还是上面那段代码,然后看一下通过消息派发执行Bird中的drink函数的步骤。
1.到自己的方法列表中去找,结果没找到。
2.去它的父类Animal中去找,发现找到了,就执行相应的逻辑。


消息派发

从中我们可以发现,如果这个方法在NSObject中,那么每次都要找好多次,就会非常慢。解决的方法就是利用方法缓存。如果调用过一次,就会放入缓存列表中,下次再调用的话,就会非常快。

swift中的函数派发

swift中函数派发包含了上述3种情况。总结如下表所示。

直接派发 函数表派发 消息派发
强制声明 static or final - dynamic
Class extensions 初始声明 extensions with @objc
Protocol extensions 初始声明 -
值类型 所有方法 - -

具体的例子可以看如下:

protocol Noisy {
     func makeNoise() -> Int  //函数表派发
}

extension Noisy {
    func makeNoise() -> Int { return 0 }  //函数表派发
    func isAnnoying() -> Bool { return true}  //直接派发
}

class Animal: Noisy {
    func makeNoise() -> Int { return 1 } //函数表派发
    func isAnnoying() -> Bool { return false } //函数表派发
    @objc func sleep() {} //函数表派发
}

extension Animal {
    func eat() {} //直接派发
    @objc func getWild() {} //消息派发
}

struct rectangle {
    func getArea() { } //直接派发
}

总的来看,具体的派发机制还是有点绕的。但是我们在选择函数派发机制时有一个原则:
1.如果不需要多态,直接派发优先考虑。
2.如果需要覆写,函数表派发优先考虑。
3.如果需要覆写和对Objective-C可见,那就用消息派发。

小结

本文主要介绍了三种常用的函数派发机制,并介绍总结了swift中的派发机制和选择时的原则。

参考

Method dispatch in Swift

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容

  • 原文: Method Dispatch in Swift作者: Brain King译者: kemchenj 译者...
    kemchenj阅读 9,059评论 11 91
  • 量大的人,成就也大;气量小的人,为小事所拘,故难成大事。 有一对小夫妻吵架。男人说:“老人送的是一片心意,无论送的...
    醉后挥毫笔有神阅读 269评论 0 0
  • 没有网络的大山里,一切都是根据原始“日出而作,日落而息”的时间表。 到达七藏沟第一天,连续阴雨天,只是没想到半夜十...
    刘月Luna阅读 277评论 4 2
  • 背景 学习IT其实大部分也是学习概念,今天我在一个技术分享群里看到内部框架由阻塞是改成非阻塞式(基于netty的)...
    shawnxjf阅读 903评论 0 1
  • 有些誓言许下太易,付出却是一生,赢一辈子还是输一世人,都在一句话,你愿意吗?爱她,忠诚于她。 有些诗句写了太妙,竭...
    靛羽风涟阅读 155评论 0 0