本文主要分為兩部分, 第一部分是講解類方法load和initialize的區(qū)別; 第二部分是一些相關(guān)的面試題.
一. 類方法load和initialize的區(qū)別
Objective-C作為一門面向?qū)ο笳Z言吕朵,有類和對象的概念。編譯后了嚎,類相關(guān)的數(shù)據(jù)結(jié)構(gòu)會保留在目標(biāo)文件中碗殷,在運(yùn)行時(shí)得到解析和使用。在應(yīng)用程序運(yùn)行起來的時(shí)候挺份,類的信息會有加載和初始化過程。 就像Application有生命周期回調(diào)方法一樣贮懈,在Objective-C的類被加載和初始化的時(shí)候匀泊,也可以收到方法回調(diào)优训,可以在適當(dāng)?shù)那闆r下做一些定制處理。而這正是load和initialize方法可以幫我們做到的各聘。
@interface NSObject <NSObject> {
+ (void)load;
+ (void)initialize;
@end
1.1 load
- 調(diào)用時(shí)機(jī)
官方解釋: 運(yùn)行時(shí)揣非,添加類或者分類的時(shí)候調(diào)用.
個(gè)人理解: +load
方法在這個(gè)文件被程序裝載時(shí)調(diào)用.只要是在Compile Sources
中出現(xiàn)的文件總是會被裝載,這與這個(gè)類是否被用到無關(guān)躲因,因此+load
方法總是在main函數(shù)之前調(diào)用.
- 調(diào)用次數(shù)
因?yàn)?code>+load是runtime
加載類早敬、分類的時(shí)候調(diào)用, 所以只會調(diào)用<math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="red"><mn>1</mn></mstyle></mrow></semantics></math>1次.
- 調(diào)用方式
會循環(huán)調(diào)用所有類的+load
方法. 注意,這里是(調(diào)用分類的+load
方法也是如此)直接使用函數(shù)內(nèi)存地址的方式(*load_method)(cls, SEL_load)
對+load
方法進(jìn)行調(diào)用的大脉,而不是使用發(fā)送消息objc_msgSend
的方式搞监。
- 調(diào)用順序
+load
方法加載順序:父類> 子類> 分類.
+load
方法不會被覆蓋(比如有父類,子類镰矿,分類A琐驴,分類B,這四個(gè)load方法都會加載).
注意1:(如果分類中有A,B,順序要看A,B加入工程中順序) , 可能結(jié)果:( 父類> 子類> 分類A> 分類B ) 或者( 父類> 子類> 分類B> 分類A ).
注意2:分類中無父子關(guān)系, 依賴Compile Sources
的上下順序來調(diào)用秤标,上面的優(yōu)先調(diào)用.
1.2 initialize
- 調(diào)用時(shí)機(jī)
+initialize
方法是在類或它的子類收到第一條消息之前被調(diào)用的绝淡,這里所指的消息包括實(shí)例方法和類方法的調(diào)用,并且只會調(diào)用一次苍姜。initialize
方法實(shí)際上是一種惰性調(diào)用牢酵,也就是說如果一個(gè)類一直沒被用到,那它的initialize
方法也不會被調(diào)用怖现,這一點(diǎn)有利于節(jié)約資源.
- 調(diào)用次數(shù)
因?yàn)?code>+initialize自己沒有實(shí)現(xiàn)的情況下就會去找父類的, 所以調(diào)用次數(shù)不確定.
- 調(diào)用方式
runtime
使用了發(fā)送消息objc_msgSend
的方式對+initialize
方法進(jìn)行調(diào)用茁帽。也就是說+initialize
方法的調(diào)用與普通方法的調(diào)用是一樣的,走的都是發(fā)送消息的流程屈嗤。換言之潘拨,如果子類沒有實(shí)現(xiàn)+initialize
方法,那么繼承自父類的實(shí)現(xiàn)會被調(diào)用饶号;如果一個(gè)類的分類實(shí)現(xiàn)了+initialize
方法铁追,那么就會對這個(gè)類中的實(shí)現(xiàn)造成覆蓋。
- 調(diào)用順序
1.當(dāng)調(diào)用子類的+initialize
方法時(shí)候,先調(diào)用父類的,如果父類有分類, 那么分類的+initialize
會覆蓋掉父類的. 2.分類的+initialize
會覆蓋掉父類的 3.子類的+initialize
不會覆蓋分類的 4.父類的+initialize
不一定會調(diào)用, 因?yàn)橛锌赡芨割惖姆诸愔貙懥怂?/p>
- eg1:當(dāng)工程中Person主類有initialize茫船,分類不存在initialize琅束,調(diào)用
[Son new]
結(jié)果如下:
+[Person initialize]
+[Son initialize]
- eg2:當(dāng)工程中Person主類有或無initialize,分類存在initialize算谈,調(diào)用
[Son new]
結(jié)果如下:
+[Person(Ability) initialize]
+[Son initialize]
- eg3:當(dāng)工程中Person主類有initialize涩禀,分類和子類不存在initialize,調(diào)用
[Son new]
結(jié)果如下:
+[Person initialize]
+[Person initialize]
- eg4:當(dāng)工程中Person主類有或無initialize然眼,分類存在initialize, 子類不存在initialize艾船,調(diào)用
[Son new]
結(jié)果如下:
+[Person(Ability) initialize]
+[Person(Ability) initialize]
- 注意點(diǎn)
- initialize的自然調(diào)用是在第一次主動(dòng)使用當(dāng)前類的時(shí)候.
- 關(guān)于繼承:和load不同,即使子類不實(shí)現(xiàn)initialize方法,會把父類的實(shí)現(xiàn)繼承過來調(diào)用一遍屿岂,就是會沿用父類的+initialize.(沿用父類的方法中践宴,self還是指子類)
- 父類和本類的調(diào)用:子類的+initialize將要調(diào)用時(shí)會激發(fā)父類調(diào)用的+initialize方法,所以也不需要在子類寫明[super initialize].
- 多個(gè)分類就看
Compile Sources
的順序爷怀,只執(zhí)行一個(gè)Category的+initialize方法, 也就是<math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="red"><mtext>最下面的那個(gè)分類</mtext></mstyle></mrow></semantics></math>最下面的那個(gè)分類)
1.3 總結(jié)
標(biāo)題 | +load | +initialize |
---|---|---|
調(diào)用時(shí)機(jī) | 被添加到runtime時(shí) | 收到第一條消息前, 也可能用于那也不會調(diào)用 |
調(diào)用順序 | 父類 > 本類 > 分類 | 父類 > 本類 (如果有分類就是分類最大) |
若自身未實(shí)現(xiàn), 是否沿用父類方法 | 否 | 是 |
線程安全 | 安全 | 安全 |
類別中的定義 | 全部都會執(zhí)行, 但是灰分先后順序 | 不會全部執(zhí)行, 存在方法的覆蓋 |
注意:
- 在使用時(shí)都不要過重地依賴于這兩個(gè)方法阻肩,除非真正必要。
- 謹(jǐn)慎在分類中實(shí)現(xiàn)
+initialize
方法运授,因?yàn)槿绻诜诸愔袑?shí)現(xiàn)了烤惊,本類實(shí)現(xiàn)的+initialize
方法將不會被調(diào)用。 - 謹(jǐn)慎在分類中實(shí)現(xiàn)
+load
方法吁朦。因?yàn)槿绻诒绢愔袑?shí)現(xiàn)+load
方法混淆A撕氧、B兩個(gè)方法,分類中也混淆A喇完、B,因?yàn)楸绢惡头诸惖?code>+load都實(shí)現(xiàn)了剥啤,所以都會調(diào)用锦溪,A、B在本類中置換后府怯,又在分類中置換了回來刻诊。 - load方法通常用來進(jìn)行Method Swizzle,initialize方法一般用于初始化全局變量或靜態(tài)變量牺丙。
- load和initialize方法內(nèi)部使用了鎖则涯,因此它們是線程安全的。實(shí)現(xiàn)時(shí)要盡可能保持簡單冲簿,避免阻塞線程粟判,不要再使用鎖。
二. 常見的相關(guān)面試題
2.1 主類和分類有同名方法時(shí)的調(diào)用順序
eg: 主類和分類有同名方法峦剔,分類會覆蓋主類的方法档礁。最后只保留一個(gè)同名方法
比如:主類Person和分類Person+A都有commonClsMethod類方法,執(zhí)行程序結(jié)果如下:
+[Person(A) commonClsMethod]
2.2 load/initialize需不需要在子類的實(shí)現(xiàn)中顯式地調(diào)用父類的實(shí)現(xiàn)
super的方法會成功調(diào)用吝沫,但是這是多余的呻澜,因?yàn)?code>runtime會自動(dòng)對父類的+load
方法進(jìn)行調(diào)用,而+initialize
則會隨子類自動(dòng)激發(fā)父類的方法不需要顯示調(diào)用惨险。另一方面羹幸,如果父類中的方法用到的self
,其指代的依然是類自身辫愉,而不是父類栅受。
三. 結(jié)語
路漫漫其修遠(yuǎn)兮,吾將上下而求索~
.End