從一個(gè)iOS應(yīng)用啟動(dòng)開始說(shuō)起

筆者嘗試線性描述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):

  1. 先給所有的父類發(fā)送一個(gè)+load消息。
    應(yīng)該是先找到繼承鏈。如:Children —> Parent —>NSObject。
    根據(jù)NSObject —>Parent —>Children的順序依次發(fā)送+initilize消息。

  2. [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)用。

  3. 特別注意:每個(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ā)者操心了。

4.我碰一碰屏幕,后面發(fā)生了什么

5.runtime關(guān)我什么事

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容