Swift 函数的派发方法
static func 会变成直接派发 direct dispatch
重点探讨 dynamic
& @objc
1.swift
1 2 3
| class PigeonError { dynamic func wrapResult() {} }
|
生成对应 sil 中间代码并且替换 shadow name
1
| $ swiftc 1.swift -emit-silgen | xcrun swift-demangle > 1.out
|
dynamic func
compare with @objc func
几个关键区别,dynamic 多了 dynamically_replacable,说明其动态可替换
1 2 3 4 5 6 7
| class PigeonError { dynamic func wrapResult() {} }
+++ sil hidden [dynamically_replacable] [ossa] @main.PigeonError.wrapResult() -> () : $@convention(method) (@guaranteed PigeonError) -> () { ... }
|
@objc 多了 objc_method,一个暴露给 objc runtime 的壳方法,copy_value & borrow PigeonError实例,再 call 源函数,再 return。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class PigeonError { @objc func wrapResult() @objc deinit init() }
sil private [thunk] [ossa] @@objc main.PigeonError.wrapResult() -> () : $@convention(objc_method) (PigeonError) -> () {
bb0(%0 : @unowned $PigeonError): %1 = copy_value %0 : $PigeonError %2 = begin_borrow %1 : $PigeonError %3 = function_ref @main.PigeonError.wrapResult() -> () : $@convention(method) (@guaranteed PigeonError) -> () %4 = apply %3(%2) : $@convention(method) (@guaranteed PigeonError) -> () end_borrow %2 : $PigeonError destroy_value %1 : $PigeonError return %4 : $() }
|
两者皆是 vtable dispatch 方法,@objc 并未使用消息派发机制
1 2 3 4 5
| sil_vtable PigeonError { #PigeonError.wrapResult: (PigeonError) -> () -> () : @main.PigeonError.wrapResult() -> () #PigeonError.init!allocator: (PigeonError.Type) -> () -> PigeonError : @main.PigeonError.__allocating_init() -> main.PigeonError #PigeonError.deinit!deallocator: @main.PigeonError.__deallocating_deinit }
|
@objc dynamic func
与 objc 唯一区别就是,func wrapResult 从 vtable中去掉了,说明转为objc 消息发送了
1 2 3 4
| sil_vtable PigeonError { #PigeonError.init!allocator: (PigeonError.Type) -> () -> PigeonError : @main.PigeonError.__allocating_init() -> main.PigeonError #PigeonError.deinit!deallocator: @main.PigeonError.__deallocating_deinit }
|
objc.out
dynamic.out
objc_dynamic.out
static.out