事情緣起于全局變量初始化沟于。眾所周知,全局變量只有像整數(shù)植康、字符串等才可以直接在.m文件初始化旷太,而NSArray、NSColor等不能直接初始化值销睁。要讓這些全局變量只初始化一次泳秀,有+load、+initialize和attribute((constructor))三種方式可選榄攀。
1. load
load方法是類在被運行時加載的時候調(diào)用
- 父類在子類前調(diào)用嗜傅;依賴的framework先調(diào)用。
- 如果類沒有實現(xiàn)此靜態(tài)方法檩赢,則不調(diào)用
- 本類和Category都實現(xiàn)了load吕嘀,則都調(diào)用,且本類先調(diào)用
load最大的問題是不同的類調(diào)用順序不確定贞瞒。比如代碼有A和B兩個類偶房。在A類load時候調(diào)用父類或framework里的類沒問題,調(diào)用B類就不確定了军浆。
2. initialize
initialize只有在類被第一次使用的時候調(diào)用棕洋,這種懶加載的方式很有誘惑力。然而乒融,initialize最大的缺陷是它是基于OC消息機制掰盘。所以,如果子類沒有實現(xiàn)initialize赞季,那么會繼續(xù)向父類發(fā)消息愧捕,直到找到為止。因此申钩,如果類A實現(xiàn)initialize次绘,A的子類Aa沒實現(xiàn)。假如A和Aa都被用到撒遣,A的initialize方法就會被調(diào)用2次邮偎。
通常這不是我們本意,常見的做法是在initialize方法里判斷self是不是本類义黎。
3. attribute((constructor))
則個是GCC的擴展語法(黑魔法)禾进,由它修飾過的函數(shù),會在main函數(shù)之前調(diào)用轩缤。原理是在ELF的.ctors段增加一條函數(shù)引用命迈,加載器在執(zhí)行main函數(shù)前,檢查.ctror section火的,并執(zhí)行里面的函數(shù)壶愤。如果有多個attribute((constructor))修飾的函數(shù)有依賴,他們調(diào)用順序是不確定的(應(yīng)該也沒人真的這樣干吧)馏鹤。
上面三種方法在app中的調(diào)用順序是
load -> attribute((constructor)) -> main -> initialize
initialize的性能不錯征椒,不會影響程序啟動。然而最大的缺陷是湃累,要保證這些全局變量只被自己使用勃救,等自己初始化后別人才能使用,而且治力,initialize容易寫錯導(dǎo)致多次調(diào)用蒙秒。除非是那種比較耗資源的對象,一般不用宵统。load在繼承順上有保證晕讲,而且還能在Category中使用,特定的場合很適用马澈。比如這個iOSViewArchDemo1瓢省。綜上,attribute((constructor))應(yīng)該是最適合的一般初始化選擇痊班。
大家怎么看勤婚?