iOS weak修飾屬性的原理

一因块、weak基本用法

weak是弱引用震贵,用weak來修飾淹魄、描述所引用對象的計數(shù)器并不會加1郁惜,而且weak會在引用對象被釋放的時候自動置為nil,這也就避免了野指針訪問壞內(nèi)存而引起奔潰的情況甲锡,另外weak也可以解決循環(huán)引用兆蕉。

拓展:為什么修飾代理使用weak而不是用assign?

assign可用來修飾基本數(shù)據(jù)類型缤沦,也可修飾OC的對象虎韵,但如果用assign修飾對象類型指向的是一個強指針,當(dāng)指向的這個指針釋放之后缸废,它仍指向這塊內(nèi)存包蓝,必須要手動給置為nil驶社,否則會產(chǎn)生野指針,如果還通過此指針操作那塊內(nèi)存测萎,會導(dǎo)致EXC_BAD_ACCESS錯誤亡电,調(diào)用了已經(jīng)被釋放的內(nèi)存空間;而weak只能用來修飾OC對象硅瞧,而且相比assign比較安全份乒,如果指向的對象消失了,那么它會自動置為nil腕唧,不會導(dǎo)致野指針或辖。

二、weak原理概括

weak表其實是一個哈希表枣接,key是所指對象的指針颂暇,value是weak指針的地址數(shù)組。(value是數(shù)組的原因是:因為一個對象可能被多個弱引用指針指向)

Runtime維護了一張weak表但惶,用來存儲某個對象的所有的weak指針蟀架。

weak原理實現(xiàn)過程三步驟

初始化開始時,會調(diào)用objc_initWeak函數(shù)榆骚,初始化新的weak指針指向?qū)ο蟮牡刂?/b>

2.緊接著片拍,objc_initWeak函數(shù)里面會調(diào)用objc_storeWeak() 函數(shù),objc_storeWeak() 函數(shù)的作用是用來更新指針的指向妓肢,創(chuàng)建弱引用表捌省。

3.在最后會調(diào)用clearDeallocating函數(shù)。而clearDeallocating函數(shù)首先根據(jù)對象的地址獲取weak指針地址的數(shù)組碉钠,然后緊接著遍歷這個數(shù)組纲缓,將其中的數(shù)組開始置為nil,把這個entry從weak表中刪除喊废,最后一步清理對象的記錄祝高。

拓展:詳細(xì)步驟

初始化開始時,會調(diào)用objc_initWeak函數(shù)污筷,初始化新的weak指針指向?qū)ο蟮牡刂?/p>

當(dāng)我們初始化weak變量時工闺,runtime會調(diào)用NSObject.mm中的objc_initWeak,而objc_initWeak函數(shù)里面的實現(xiàn)如下:

idobjc_initWeak(id*location,id newObj) {// 查看對象實例是否有效,無效對象直接導(dǎo)致指針釋放if(!newObj) {

? ? ? ? *location = nil;

? ? ? ? return nil;

? ? }

? ? // 這里傳遞了三個 bool 數(shù)值

? ? // 使用 template 進行常量參數(shù)傳遞是為了優(yōu)化性能returnstoreWeakfalse/*old*/,true/*new*/,true/*crash*/>? ? (location, (objc_object*)newObj);

}

通過上面代碼可以看出瓣蛀,objc_initWeak()函數(shù)首先判斷指針指向的類對象是否有效陆蟆,無效,直接返回惋增;否則通過storeWeak()被注冊為一個指向value的_weak對象

 2.?objc_initWeak函數(shù)里面會調(diào)用objc_storeWeak() 函數(shù)叠殷,objc_storeWeak() 函數(shù)的作用是用來更新指針的指向,創(chuàng)建弱引用表诈皿。

3..在最后會調(diào)用clearDeallocating函數(shù)林束。而clearDeallocating函數(shù)首先根據(jù)對象的地址獲取weak指針地址的數(shù)組像棘,然后緊接著遍歷這個數(shù)組,將其中的數(shù)組開始置為nil壶冒,把這個entry從weak表中刪除缕题,最后一步清理對象的記錄。

問:當(dāng)weak指向的對象被釋放時依痊,如何讓weak指針置為nil的呢?

1怎披、調(diào)用objc_release2胸嘁、因為對象的引用計數(shù)為0,所以執(zhí)行dealloc3凉逛、在dealloc中性宏,調(diào)用了_objc_rootDealloc函數(shù)4、在_objc_rootDealloc中状飞,調(diào)用了object_dispose函數(shù)5毫胜、調(diào)用objc_destructInstance6、最后調(diào)用objc_clear_deallocating,詳細(xì)過程如下:

? a. 從weak表中獲取廢棄對象的地址為鍵值的記錄

? b. 將包含在記錄中的所有附有 weak修飾符變量的地址诬辈,賦值為? nil

? c. 將weak表中該記錄刪除

? d. 從引用計數(shù)表中刪除廢棄對象的地址為鍵值的記錄

objc_initWeak()函數(shù)將附有__weak修飾符的變量初始化為0后,

將賦值對象b作為參數(shù)調(diào)用objc_storeWeak()函數(shù).

objc_storeWeak函數(shù)把第二個參數(shù)(賦值對象b)的內(nèi)存地址作為鍵值key酵使,將第一個參數(shù)(weak修飾的屬性變量a)的內(nèi)存地址(&a)作為value,注冊到 weak 表中焙糟。如果第二個參數(shù)(b)為0(nil)口渔,那么把變量(a)的內(nèi)存地址(&a)從weak表中刪除。

(也就是初始化一個新的weak指針指向?qū)ο蟮膬?nèi)存地址,objc_storeWeak()函數(shù)的作用是更新指針指向,創(chuàng)建對應(yīng)的弱引用表.)

把objc_storeWeak(&a, b)理解為:objc_storeWeak(value, key)穿撮,并且當(dāng)key變nil缺脉,將value置nil。

在b非nil時悦穿,a和b指向同一個內(nèi)存地址攻礼,在b變nil時,a變nil栗柒。此時向a發(fā)送消息不會崩潰:在Objective-C中向nil發(fā)送消息是安全的礁扮。

而如果a是由assign修飾的,則: 在b非nil時瞬沦,a和b指向同一個內(nèi)存地址深员,在b變nil時,a還是指向該內(nèi)存地址蛙埂,變野指針倦畅。此時向a發(fā)送消息極易崩潰。

作用:作為一種弱引用屬性修飾詞绣的,不增加對象的引用計數(shù)叠赐,也不持有對象欲账,對象消失后,指針自動變成nil

原理:weak 其實是一個 hash(哈希)表芭概,Key:對象的地址赛不,Value:weak 指針的地址數(shù)組

底層實現(xiàn)過程

初始化時:runtime會調(diào)用objc_initWeak函數(shù),初始化一個新的weak指針指向?qū)ο蟮牡刂?/p>

添加引用時:objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù)罢洲, objc_storeWeak() 的作用是更新指針指向踢故,創(chuàng)建對應(yīng)的弱引用表

釋放時:調(diào)用clearDeallocating函數(shù),對象地址獲取所有weak指針地址的數(shù)組惹苗,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil

之前只是認(rèn)識到 weak 作為一種弱引用屬性修飾詞殿较,不增加對象的引用計數(shù),也不持有對象桩蓉,對象消失后淋纲,指針自動變成nil。在ARC環(huán)境下院究,為避免循環(huán)引用洽瞬,往往會把delegate屬性用weak修飾。

今天整理一下 weak 的實現(xiàn)原理业汰,先概括的講 weak 其實是一個 hash(哈希)表伙窃,Key 是所指對象的地址,Value 是 weak 指針的地址數(shù)組样漆。

實現(xiàn)原理

Runtime維護了一個weak表对供,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash(哈希)表氛濒,Key是所指對象的地址产场,Value是weak指針的地址(這個地址的值是所指對象的地址)數(shù)組。

底層的實現(xiàn)大體分為三步:

1.初始化時:runtime會調(diào)用objc_initWeak函數(shù)舞竿,初始化一個新的weak指針指向?qū)ο蟮牡刂肪┚啊#ńo你添個干兄弟)

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表中刪除伴逸,最后清理對象的記錄洲愤。(最后等這個干兄弟干完活后,被卸磨殺驢)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末束世,一起剝皮案震驚了整個濱河市后添,隨后出現(xiàn)的幾起案子馅精,更是在濱河造成了極大的恐慌洲敢,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件询一,死亡現(xiàn)場離奇詭異菱阵,居然都是意外死亡嫡锌,警方通過查閱死者的電腦和手機槽卫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茸塞,“玉大人躲庄,你說我怎么就攤上這事〖嘏埃” “怎么了噪窘?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長效扫。 經(jīng)常有香客問我倔监,道長,這世上最難降的妖魔是什么菌仁? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任浩习,我火速辦了婚禮,結(jié)果婚禮上济丘,老公的妹妹穿的比我還像新娘谱秽。我一直安慰自己,他們只是感情好摹迷,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布疟赊。 她就那樣靜靜地躺著,像睡著了一般峡碉。 火紅的嫁衣襯著肌膚如雪近哟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天异赫,我揣著相機與錄音椅挣,去河邊找鬼。 笑死塔拳,一個胖子當(dāng)著我的面吹牛鼠证,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播靠抑,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼量九,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荠列,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤类浪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肌似,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體费就,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年川队,在試婚紗的時候發(fā)現(xiàn)自己被綠了力细。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡固额,死狀恐怖眠蚂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斗躏,我是刑警寧澤逝慧,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站啄糙,受9級特大地震影響笛臣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迈套,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一捐祠、第九天 我趴在偏房一處隱蔽的房頂上張望碱鳞。 院中可真熱鬧桑李,春花似錦、人聲如沸窿给。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崩泡。三九已至禁荒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間角撞,已是汗流浹背呛伴。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谒所,地道東北人热康。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像劣领,于是被迫代替她去往敵國和親姐军。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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