筆者嘗試線性描述iOS開發(fā)中經(jīng)常遇到的場(chǎng)景以及其背后機(jī)理,算是對(duì)一年iOS開發(fā)經(jīng)驗(yàn)的總結(jié)。描述不到位或者有誤的地方在所難免,還望指點(diǎn)一二,BTW,本文將會(huì)做持續(xù)更新。。。 : )
本文嘗試從:load 、initilize到窗口建立。
控制器及其視圖的建立以及跟窗口的關(guān)系。
為什么說(shuō)iOS程序就是個(gè)死循環(huán)(我們需要死循環(huán))-RunLoop。
事件的響應(yīng)者鏈 -- 聯(lián)想:每個(gè)用戶觸發(fā)的事件,使應(yīng)用程序內(nèi)部對(duì)象相機(jī)作用或者界面發(fā)生變化(或者產(chǎn)生轉(zhuǎn)場(chǎng)(控制器切換))里邊iOS都給我們提供了切入點(diǎn),如何才能自定義響應(yīng)、自定義轉(zhuǎn)場(chǎng)效果等。在其看來(lái)就是執(zhí)行相應(yīng)的關(guān)鍵回調(diào)。
runtime是什么?三種交互方式。
調(diào)一個(gè)方法怎么啦?不同級(jí)別的程序員的看法。
等這些個(gè)方面細(xì)說(shuō)發(fā)生在指尖下的那些“小事兒”。對(duì),我們需要清楚這些小事。
0.啟動(dòng)
+load
程序被啟動(dòng)后,在main函數(shù)被調(diào)用之前,iOS系統(tǒng)為應(yīng)用做了很多準(zhǔn)備工作這毋庸置疑,其中就會(huì)涉及到【把類加載到運(yùn)行時(shí)系統(tǒng)】,事畢,該類的+load方法會(huì)被調(diào)用,我們可以在此做一些萌萌噠的事情,比如互換兩個(gè)方法的實(shí)現(xiàn)這種有意思的事情:把系統(tǒng)的一個(gè)方法a跟自定義的方法b互換,然后方法b里做的事情就是調(diào)用方法b,還有做自己喜歡做的事情。如下邊干的:
@implementation UITableView (MJRefresh)
+ (void)load
{
[self exchangeInstanceMethod1:@selector(reloadData) method2:@selector(mj_reloadData)];
}
- (void)mj_reloadData
{
[self mj_reloadData];
[self executeReloadDataBlock];
}
那每次給UITableView對(duì)象發(fā)reloadData消息的時(shí)候,就會(huì)做多一件事情:
[self executeReloadDataBlock];
這就是重載+load方法的用處 :
implement this method to perform class-specific behavior upon loading.
另外:
- 一個(gè)類的+load方法是在其所有父級(jí)類調(diào)完+load方法后才被調(diào)用的。
- 一個(gè)類別的+load方法在類的本體+load方法調(diào)用之后才被調(diào)用。
注意:別隨便給其他類發(fā)消息,因?yàn)榭赡芩麄冞€沒(méi)有被加載起來(lái)。
+ initialize
第一次使用一個(gè)類的時(shí)候,類的+initialize方法會(huì)被調(diào)用,用于初始化這個(gè)類。多用于初始化類的靜態(tài)變量。
【特別注意】:由于運(yùn)行時(shí)系統(tǒng)在調(diào)用這個(gè)方法的時(shí)候:
Superclasses receive this message before their subclasses.
父類先收到這個(gè)消息,然后才是子類。
因此,當(dāng)【給子類發(fā)initialize消息的時(shí)候,如果子類沒(méi)有重載+initialize方法】。那會(huì)出現(xiàn):
先給所有的父類發(fā)送一個(gè)+load消息。
應(yīng)該是先找到繼承鏈。如:Children —> Parent —>NSObject。
根據(jù)NSObject —>Parent —>Children的順序依次發(fā)送+initilize消息。-
[Childen initialize]-也就是在給Childen 發(fā)送initialize消息時(shí),在當(dāng)前類-Children 的方法列表找不到+initialize方法,會(huì)在Parant里找到此方法,所以要在此處做判斷,receiver必須得是本類方可執(zhí)行initialize具體操作。也就是需要在+initialize方法加上這么幾行判斷:
+ (void)initialize { if (self == [ClassName self]) { // ... do the initialization ... } }這樣一來(lái),對(duì)應(yīng)的類就不會(huì)被重復(fù)做初始化操作了。盡管+initialize方法還是會(huì)被調(diào)用。
-
特別注意:每個(gè)類的+initialize只會(huì)被調(diào)用一次。也就是說(shuō),如果代碼中Parent類的使用是在Children后邊,也不會(huì)繼續(xù)給Parent對(duì)象發(fā)+initialize方法了。那是因?yàn)榻oChildren發(fā)initialize的時(shí)候,已經(jīng)觸發(fā)了父類的initialize。
總結(jié):重載+initialize方法,需在里邊判斷消息的接收者是不是本類對(duì)象。是才做初始化工作。
如果不加判斷,那么當(dāng)其子類沒(méi)有重載initialize的時(shí)候,這個(gè)方法會(huì)被執(zhí)行,也就是初始化的邏輯會(huì)被重復(fù)執(zhí)行。
1.窗口(window)的建立
2.視圖控制器跟窗口有什么關(guān)系
3.每一個(gè)iOS應(yīng)用都是一個(gè)死循環(huán)
首先,我們?cè)O(shè)想一下一個(gè)場(chǎng)景:程序啟動(dòng)后,我沒(méi)干什么事情,程序你就靜靜的待著,別使用cpu了,我點(diǎn)擊一個(gè)按鈕或者滑動(dòng)屏幕,你得給我及時(shí)響應(yīng)。
重復(fù)一遍就是:沒(méi)事干的時(shí)候線程休眠,有事干的時(shí)候喚醒線程執(zhí)行任務(wù)。每次任務(wù)執(zhí)行完了之后就卡在一個(gè)點(diǎn)上休眠,這個(gè)點(diǎn)就是對(duì)事件的監(jiān)聽。
蘋果老早就處理好這些東西了,已經(jīng)不大需要我們開發(fā)者操心了。