[翻譯]Obejective-C的類加載與初始化

作爲一個iOS程序員,你一般情況下並不需要關心類是如何加載到內存裏的。這是一個複雜的過程,由運行時處理的,並早於你的代碼運行。
對於大部分的類,你只需要知道如何使用即可,但是有些時候,你要做一些特殊的處理,比如一個某個類想創建一個全局的表,用來加載本地的用戶數據或則其他一些任務。
Objective-C運行時採用兩種方式來實現這個需求:+initialize和+load。

+load

如果你在類裏實現了這個方法,只要這個類一旦加載,就會觸發+load方法。如果你在程序中或程序鏈接的動態庫中實現了該方法,此方法會在main()調用前加載,如果你在可執行的包裏實現了load方法,便會在此包加載時執行。

因爲load方法執行在程序的早期,因此你必須非常小心。很顯然,類的加載有先後,必然有些類早於另外一些類,所以在你在某個類的load方法寫代碼時,你不能保證其他類已經加載並可以調用。更嚴重的情況是,你app(框架或插件)中的某些C++的靜態初始化器,也許並未開始運行,所以如果你的代碼有賴於此,可能會引發崩潰。有一個好的情況是,你鏈接的框架(.framework)肯定會早於你的類加載,因此你可以放心使用框架裏的類。父類也會早於子類被加載,因此你也可以放心的使用父類。有一點需要注意,因爲load方法執行時,自動釋放池並未創建,因此如果你有用到內存相關的方法,請自己手動創建一個內存管理池。
load方法的一個有趣的功能是,如果你在類別裏實現了load方法,在類裏也同樣實現,他們都會被執行。這和你所知的類別可能有點出入,但是因爲load比較特別。這就意味着,你可以在load方法裏做一些特別的事情,比如方法交換。

+initialize

initialize方法執行在一個比較穩定的環境,也是比load方法更適合加代碼的地方。initialize有趣的地方在於它是懶加載的,甚至永不加載,當一個類加載時候,它不會執行。當給類發送一個消息的時候,這個類就會檢測是否已經初始化過了,如果沒有,就進行初始化。你可以認爲它執行的代碼大概如下:

id objc_msgSend(id self, SEL _cmd, ...)
    {
        if(!self->class->initialized)
            [self->class initialize];
        ...send the message...
    }

當然,實際上肯定比上面的代碼複雜,因爲涉及到線程安全及其他。因此我們可以知道,一個類的initialize方法只會執行一次,並且會在此類收到第一個消息的時候執行。和load一樣,initialize消息會在本類處理前,會先將消息發送給它所有的父類(譯者注:load是實現了就會執行,initialize是發送了消息肯定會執行,如果本身沒實現,就會執行繼承於父類的方法),之後再自己處理消息。
使用initialize會比load更安全,因爲不需要太考慮時間點。而且肯定是在UIApplicationmain()之後。
由於initialize的懶運行,因此不適合在裏面註冊類,
這個特性,讓你可以使用initialize更任性,而且你可以不用擔心在類加載時候浪費資源。
在使用initialize的時候,你需要注意一點,在我們上面嵌入的代碼中,有執行[self->class initialize],這意味着,如果你的類未實現此方法,就會調用繼承自父類的initialize方法。正因如此,你最好在代碼中加入判斷:

 + (void)initialize
    {
        if(self == [WhateverClass class])
        {
            ...perform initialization...
        }
    }

如果你不加入判斷,如果有一個子類繼承於它,你寫的initialize方法可能會執行多次,即時子類沒有實現自身的initialize方法。就算你沒有子類,但是當你此類使用到蘋果的kvo/kvc機制,也會幫你生成一個子類。

原文: http://math.stackexchange.com/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章