【iOS】weak的底層實(shí)現(xiàn)

轉(zhuǎn)載自:【iOS】weak的底層實(shí)現(xiàn)

weak底層千千萬,吾竟裝作看不見...
weak基本用法

weak是弱引用,用weak描述修飾或者所引用對象的計數(shù)器不會加一,并且會在引用的對象被釋放的時候自動被設(shè)置為nil,大大避免了野指針訪問壞內(nèi)存引起崩潰的情況,另外weak還可以用于解決循環(huán)引用唆姐。

weak原理概括

weak表其實(shí)是一個hash(哈希)表,Key是所指對象的地址廓八,Value是weak指針的地址數(shù)組奉芦。weak的底層實(shí)現(xiàn)的原理是什么赵抢?

Runtime維護(hù)了一個weak表,用于存儲指向某個對象的所有weak指針声功。weak表其實(shí)是一個hash表烦却,Key是所指對象的地址,value是weak指針的地址(這個地址的值是所指對象指針的地址)數(shù)組先巴。

為什么value是數(shù)組其爵?因為一個對象可能被多個弱引用指針指向

weak原理實(shí)現(xiàn)步驟

weak 的實(shí)現(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實(shí)現(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() 方法的實(shí)現(xiàn)如下:

id objc_initWeak(id *location, id newObj) {
// 查看對象實(shí)例是否有效,無效對象直接導(dǎo)致指針釋放
    if (!newObj) {
        *location = nil;
        return nil;
    }
    // 這里傳遞了三個 bool 數(shù)值
    // 使用 template 進(jìn)行常量參數(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() 的具體實(shí)現(xiàn),請參考weak弱引用實(shí)現(xiàn)的方式,這里的實(shí)現(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ù)表中刪除廢棄對象的地址為鍵值的記錄
拓展補(bǔ)充

weak描沟,__unsafe_unretained, unowned 與 assign區(qū)別

__unsafe_unretained: 不會對對象進(jìn)行retain,當(dāng)對象銷毀時,會依然指向之前的內(nèi)存空間(野指針)

weak: 不會對對象進(jìn)行retain,當(dāng)對象銷毀時,會自動指向nil

assign: 實(shí)質(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 也是安全的结序,自然能快一點(diǎn)是一點(diǎn)障斋。而當(dāng)情況不確定的時候,應(yīng)該優(yōu)先選用 __weak 。

unowned使用在Swift中垃环,也會分 weak 和 unowned邀层。unowned 的含義跟 __unsafe_unretained 差不多。假如很明確的知道對象的生命期遂庄,也可以選擇 unowned寥院。

致謝

參考博客:
weak 弱引用的實(shí)現(xiàn)方式
iOS 底層解析weak的實(shí)現(xiàn)原理(包含weak對象的初始化,引用涛目,釋放的分析)
個人簡書地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秸谢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子霹肝,更是在濱河造成了極大的恐慌估蹄,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沫换,死亡現(xiàn)場離奇詭異臭蚁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)讯赏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門垮兑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漱挎,你說我怎么就攤上這事系枪。” “怎么了磕谅?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵嗤无,是天一觀的道長。 經(jīng)常有香客問我怜庸,道長,這世上最難降的妖魔是什么垢村? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任割疾,我火速辦了婚禮,結(jié)果婚禮上嘉栓,老公的妹妹穿的比我還像新娘宏榕。我一直安慰自己,他們只是感情好侵佃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布麻昼。 她就那樣靜靜地躺著,像睡著了一般馋辈。 火紅的嫁衣襯著肌膚如雪抚芦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音叉抡,去河邊找鬼尔崔。 笑死,一個胖子當(dāng)著我的面吹牛褥民,可吹牛的內(nèi)容都是我干的季春。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼消返,長吁一口氣:“原來是場噩夢啊……” “哼载弄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撵颊,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤宇攻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秦驯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尺碰,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年译隘,在試婚紗的時候發(fā)現(xiàn)自己被綠了亲桥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡固耘,死狀恐怖题篷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厅目,我是刑警寧澤番枚,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站损敷,受9級特大地震影響葫笼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拗馒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一路星、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诱桂,春花似錦洋丐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肝劲,卻和暖如春迁客,著一層夾襖步出監(jiān)牢的瞬間郭宝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工哲泊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剩蟀,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓切威,卻偏偏與公主長得像育特,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子先朦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容