1.不得不知的load與initialize
總結(jié):
load和initialize的共同點
1.如果父類和子類都被調(diào)用,父類的調(diào)用一定在子類之前
+load方法要點
當(dāng)類被引用進項目的時候就會執(zhí)行l(wèi)oad函數(shù)(在main函數(shù)開始執(zhí)行之前),與這個類是否被用到無關(guān),每個類的load函數(shù)只會自動調(diào)用一次.由于load函數(shù)是系統(tǒng)自動加載的,因此不需要再調(diào)用[super load],否則父類的load函數(shù)會多次執(zhí)行考传。
1.當(dāng)父類和子類都實現(xiàn)load函數(shù)時,父類的load方法執(zhí)行順序要優(yōu)先于子類
2.當(dāng)一個類未實現(xiàn)load方法時,不會調(diào)用父類load方法
3.類中的load方法執(zhí)行順序要優(yōu)先于類別(Category)
4.當(dāng)有多個類別(Category)都實現(xiàn)了load方法,這幾個load方法都會執(zhí)行,但執(zhí)行順序不確定(其執(zhí)行順序與類別在Compile Sources中出現(xiàn)的順序一致)
5.當(dāng)然當(dāng)有多個不同的類的時候,每個類load 執(zhí)行順序與其在Compile Sources出現(xiàn)的順序一致
注意:
load調(diào)用時機比較早,當(dāng)load調(diào)用時,其他類可能還沒加載完成,運行環(huán)境不安全.
load方法是線程安全的戳葵,它使用了鎖筋量,我們應(yīng)該避免線程阻塞在load方法.
+initialize方法要點
initialize在類或者其子類的第一個方法被調(diào)用前調(diào)用植袍。即使類文件被引用進項目,但是沒有使用,initialize不會被調(diào)用筋遭。由于是系統(tǒng)自動調(diào)用打颤,也不需要顯式的調(diào)用父類的initialize,否則父類的initialize會被多次執(zhí)行漓滔。假如這個類放到代碼中编饺,而這段代碼并沒有被執(zhí)行,這個函數(shù)是不會被執(zhí)行的次和。
1.父類的initialize方法會比子類先執(zhí)行
2.當(dāng)子類不實現(xiàn)initialize方法反肋,會把父類的實現(xiàn)繼承過來調(diào)用一遍那伐。在此之前踏施,父類的方法會被優(yōu)先調(diào)用一次
3.當(dāng)有多個Category都實現(xiàn)了initialize方法,會覆蓋類中的方法,只執(zhí)行一個(會執(zhí)行Compile Sources 列表中最后一個Category 的initialize方法)
注意:
在initialize方法收到調(diào)用時,運行環(huán)境基本健全石蔗。
initialize內(nèi)部也使用了鎖,所以是線程安全的畅形。但同時要避免阻塞線程养距,不要再使用鎖
2weak的實現(xiàn)原理:
weak基本用法
weak是弱引用,用weak描述修飾或者所引用對象的計數(shù)器不會加一日熬,并且會在引用的對象被釋放的時候自動被設(shè)置為nil棍厌,大大避免了野指針訪問壞內(nèi)存引起崩潰的情況,另外weak還可以用于解決循環(huán)引用竖席。
weak原理概括
weak表其實是一個hash(哈希)表耘纱,Key是所指對象的地址,Value是weak指針的地址數(shù)組毕荐。weak的底層實現(xiàn)的原理是什么束析?
Runtime維護了一個weak表,用于存儲指向某個對象的所有weak指針憎亚。weak表其實是一個hash表员寇,Key是所指對象的地址,value是weak指針的地址(這個地址的值是所指對象指針的地址)數(shù)組第美。
為什么value是數(shù)組蝶锋?因為一個對象可能被多個弱引用指針指向
WEAK原理實現(xiàn)步驟
weak 的實現(xiàn)原理可概括三步:
1.初始化時:
runtime會調(diào)用objc_initWeak函數(shù),初始化一個新的weak指針指向?qū)ο蟮牡刂贰?/p>
2.添加引用時:
objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù)什往, objc_storeWeak() 的作用是更新指針指向扳缕,創(chuàng)建對應(yīng)的弱引用表。
3.釋放時
調(diào)用clearDeallocating函數(shù)别威。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組第献,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個entry從weak表中刪除兔港,最后清理對象的記錄庸毫。
weak實現(xiàn)三步驟詳細(xì)過程:
1、初始化時:
runtime會調(diào)用objc_initWeak函數(shù)衫樊,objc_initWeak函數(shù)會初始化一個新的weak指針指向?qū)ο蟮牡刂贰?/p>
示例代碼:
NSObject *obj = [[NSObject alloc] init];
id __weak obj1 = obj;
當(dāng)我們初始化一個weak變量時飒赃,runtime會調(diào)用 NSObject.mm 中的objc_initWeak函數(shù)。
這個函數(shù)在Clang中的聲明如下:
id objc_initWeak(id *object, id value);
而對于 objc_initWeak() 方法的實現(xiàn)如下:
id objc_initWeak(id location, id newObj) {
// 查看對象實例是否有效,無效對象直接導(dǎo)致指針釋放
if (!newObj) {
location = nil;
return nil;
}
// 這里傳遞了三個 bool 數(shù)值
// 使用 template 進行常量參數(shù)傳遞是為了優(yōu)化性能
return storeWeakfalse/old/, true/new/, true/crash/>
(location, (objc_object*)newObj);
}
這里先判斷了其指針指向的類對象是否有效科侈,無效直接釋放返回载佳,不再往深層調(diào)用函數(shù)。否則臀栈,object將通過bjc_storeWeak函數(shù)被注冊為一個指向value的__weak對象蔫慧。
注意:
objc_initWeak函數(shù)有一個前提條件:就是object必須是一個沒有被注冊為__weak對象的有效指針。而value則可以是null权薯,或者指向一個有效的對象姑躲。
2睡扬、添加引用時:
objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù), objc_storeWeak() 的作用是更新指針指向黍析,創(chuàng)建對應(yīng)的弱引用表卖怜。
objc_storeWeak的函數(shù)聲明如下:
id objc_storeWeak(id *location, id value);
objc_storeWeak() 的具體實現(xiàn),請參考weak弱引用實現(xiàn)的方式,這里的實現(xiàn)很復(fù)雜阐枣,沒看懂马靠,沒看懂。
3蔼两、釋放時
調(diào)用clearDeallocating函數(shù)甩鳄。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil额划,最后把這個entry從weak表中刪除娩贷,最后清理對象的記錄。
當(dāng)weak引用指向的對象被釋放時锁孟,又是如何去處理weak指針的呢彬祖?當(dāng)釋放對象時,其基本流程如下:
1品抽、調(diào)用objc_release
2储笑、因為對象的引用計數(shù)為0,所以執(zhí)行dealloc
3圆恤、在dealloc中突倍,調(diào)用了_objc_rootDealloc函數(shù)
4、在_objc_rootDealloc中盆昙,調(diào)用了object_dispose函數(shù)
5羽历、調(diào)用objc_destructInstance
6、最后調(diào)用objc_clear_deallocating,詳細(xì)過程如下:
a. 從weak表中獲取廢棄對象的地址為鍵值的記錄
b. 將包含在記錄中的所有附有 weak修飾符變量的地址淡喜,賦值為 nil
c. 將weak表中該記錄刪除
d. 從引用計數(shù)表中刪除廢棄對象的地址為鍵值的記錄
拓展補充
weak秕磷,__unsafe_unretained, unowned 與 assign區(qū)別
- __unsafe_unretained: 不會對對象進行retain,當(dāng)對象銷毀時,會依然指向之前的內(nèi)存空間(野指針)
- weak: 不會對對象進行retain,當(dāng)對象銷毀時,會自動指向nil
- assign: 實質(zhì)與__unsafe_unretained等同
- unsafe_unretained也可以修飾代表簡單數(shù)據(jù)類型的property,weak也不能修飾用來代表簡單數(shù)據(jù)類型的property炼团。
- __unsafe_unretained 與 weak 比較澎嚣,使用 weak 是有代價的,因為通過上面的原理可知瘟芝,__weak需要檢查對象是否已經(jīng)消亡易桃,而為了知道是否已經(jīng)消亡,自然也需要一些信息去跟蹤對象的使用情況锌俱。也正因此晤郑,__unsafe_unretained 比 __weak快,所以當(dāng)明確知道對象的生命期時,選擇__unsafe_unretained 會有一些性能提升,這種性能提升是很微小的造寝。但當(dāng)很清楚的情況下磕洪,__unsafe_unretained 也是安全的,自然能快一點是一點匹舞。而當(dāng)情況不確定的時候,應(yīng)該優(yōu)先選用 __weak 线脚。
- unowned使用在Swift中赐稽,也會分 weak 和 unowned。unowned 的含義跟 __unsafe_unretained 差不多浑侥。假如很明確的知道對象的生命期姊舵,也可以選擇 unowned。