編譯型語(yǔ)言有三種基礎(chǔ)的派發(fā)方式: 靜態(tài)派發(fā);函數(shù)表派發(fā);消息機(jī)制派發(fā)(動(dòng)態(tài)派發(fā)).
我們都知道Objective-C是使用的消息機(jī)制派發(fā),任何的方法調(diào)用都會(huì)轉(zhuǎn)為為Objc_msgSend... 這是調(diào)用函數(shù)最動(dòng)態(tài)的方式..這方派發(fā)方式的特點(diǎn)是開發(fā)者可以在運(yùn)行時(shí)改變函數(shù)的行為.不止可以通過(guò)Method_swizzing來(lái)改變,甚至可以用isa-swizzing修改對(duì)象的繼承關(guān)系,可以實(shí)現(xiàn)自定義派發(fā).
消息機(jī)制派發(fā)這種非常動(dòng)態(tài)的特性也會(huì)造成一些問(wèn)題和它本身難以避免的問(wèn)題.(例如不易于維護(hù),可讀性和性能等問(wèn)題)
Swift作為比較年輕的高級(jí)語(yǔ)言,它會(huì)根據(jù)許多因素,在不同的地方選擇不同的派發(fā)方式.并且隨著Swift的版本也在優(yōu)化更新它的派發(fā)方式.
- 聲明的位置
- 引用類型
- 具體行為
- 顯示標(biāo)識(shí)符
最顯然的就是在Swift中創(chuàng)建NSObject類,使用Runtime的方法,那必然這些函數(shù)是動(dòng)態(tài)派發(fā)的..還有一些標(biāo)注了dynamic的函數(shù)或者屬性,他們都會(huì)使用消息機(jī)制.
我們?cè)陂_發(fā)中當(dāng)然沒(méi)有必要完全知道自己編寫的每一個(gè)函數(shù)到底是什么樣的方式派發(fā).但我們需要留意因?yàn)榕砂l(fā)方式的不同可能會(huì)造成的問(wèn)題.比如下面這個(gè)例子:
class Dog: NSObject {
var name = ""
static func ==(lhs: Dog, rhs: Dog) -> Bool {
return lhs.name == rhs.name
}
}
聲明一個(gè) Dog的類,并實(shí)現(xiàn)它的 "=="運(yùn)算符,用來(lái)比較兩個(gè)Dog的name屬性是否一致.
let dog1 = Dog()
let dog2 = Dog()
print(dog1 == dog2) // true
這兩個(gè)dog 的name都為"" ,所以 == 運(yùn)算符返回true.
但如果我們修改一下代碼.
let dog1: NSObject = Dog()
let dog2 = Dog()
print(dog1 == dog2) // false
將dog1聲明為NSObject, 我們發(fā)現(xiàn) dog1與dog2比較的時(shí)候并沒(méi)有走在Dog中聲明的== 方法, 它調(diào)用的是NSObject中的==方法,.如果你不留意Swift中靜態(tài)派發(fā)的行為...這可能和你預(yù)想的大有不同..
Swift并沒(méi)有在運(yùn)行時(shí)檢查dog1的具體類型調(diào)用它本身的 == 方法.而是在編譯階段就決定了要調(diào)用類型NSObject的 == 方法.
詳細(xì)的關(guān)于函數(shù)派發(fā)的資料參考: 參考