底層 - dealloc 的底層實(shí)現(xiàn)

官方給出的dealloc

截圖

翻譯

外部在什么情況下會(huì)觸發(fā)dealloc方法?

  • 當(dāng)一個(gè)對(duì)象retain count為0 (不再有強(qiáng)引用指向)時(shí)會(huì)觸發(fā)dealloc。

注意直接把nil賦值給一個(gè)對(duì)象,不代表一定會(huì)觸發(fā)dealloc。

dealloc 內(nèi)部實(shí)現(xiàn)方法的調(diào)用時(shí)機(jī)又是 什么?

  1. 如果開(kāi)發(fā)者實(shí)現(xiàn)了dealloc方法,那么先執(zhí)行dealloc方法中的代碼,執(zhí)行完畢后在執(zhí)行內(nèi)部實(shí)現(xiàn)。

  2. 開(kāi)發(fā)者并沒(méi)有實(shí)現(xiàn)dealloc方法的情況下,直接執(zhí)行系統(tǒng)內(nèi)部方法調(diào)用。

dealloc 方法的作用是什么 ?為什么會(huì)暴露出來(lái)給開(kāi)發(fā)者 ?

  • dealloc的作用就是釋放當(dāng)前接收器占用的內(nèi)存空間。

  • 暴露出來(lái)是提供給開(kāi)發(fā)者重寫(xiě)的 ,用來(lái)釋放編碼過(guò)程中用到的通知、Observer 等需要手動(dòng)管理釋放的操作方法。

dealloc 方法內(nèi)部都做了些什么呢 ?

dealloc流程圖

來(lái)自于 Apple 官方開(kāi)源代碼 objc4 -779 的源碼分析

一 、dealloc 調(diào)用流程

1.首先調(diào)用 _objc_rootDealloc()

第一步

2.接下來(lái)調(diào)用 rootDealloc()

屏幕快照 2020-05-07 上午11.53.33.png
  1. isTaggedPointer 是否是標(biāo)記指針 是直接 return ;

  2. 接下來(lái)會(huì)判斷是否可以被直接快速釋放,判斷的依據(jù)主要有 5 個(gè),判斷是否有以下五種情況

  1. nonpointer 是否優(yōu)化過(guò)isa指針

  2. weakly_reference 是否存在弱引用指向

  3. has_assoc 是否設(shè)置過(guò)關(guān)聯(lián)對(duì)象

  4. has_cxx_dtor 是否有cpp的析構(gòu)函數(shù)(.cxx_destruct)

  5. has_sidetable_rc 引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中

  1. 如果有以上五種任意一種,將會(huì)調(diào)用 object_dispose()方法,做下一步的處理。

  2. 如果沒(méi)有之前五種情況的任意一種,則可以執(zhí)行釋放操作,C 函數(shù)的 free()。

  3. 執(zhí)行完畢。

步驟3到5

二、object_dispose() 調(diào)用流程。

  1. 直接調(diào)用 objc_destructInstance()。

  2. 之后調(diào)用C的 free() 函數(shù)。

_object_dispose
  1. objc_destructInstance() 調(diào)用流程

    1. 先判斷 hasCxxDtor,是否有析構(gòu)函數(shù)(析構(gòu)器),要調(diào)用 object_cxxDestruct() ,釋放(清除成員變量)。

    2. 再判斷hasAssocitatedObjects,如果有的話(huà),要調(diào)用object_remove_associations(), 移除當(dāng)前對(duì)象的關(guān)聯(lián)對(duì)象。

    3. 然后調(diào)用 objc_clear_deallocating()。

    4. 執(zhí)行完畢。


      屏幕快照 2020-05-07 下午12.06.20.png
  2. objc_clear_deallocating() 調(diào)用流程。

    1. 調(diào)用clearDeallocating()


      屏幕快照 2020-05-07 下午12.09.53.png
    2. 判斷isa是否優(yōu)化過(guò),從arm64架構(gòu)開(kāi)始,對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)共用體(union)結(jié)構(gòu),所以結(jié)果一般是優(yōu)化過(guò)了。

    3. 判斷是否有弱引用或者引用計(jì)數(shù)

    4. 執(zhí)行 clearDeallocating_slow()


      步驟2到4
    5. 再執(zhí)行 weak_clear_no_lock,在這一步驟中,會(huì)將指向該對(duì)象的弱引用指針置為nil。

    6. 接下來(lái)執(zhí)行 table.refcnts.eraser(),從引用計(jì)數(shù)表中擦除該對(duì)象的引用計(jì)數(shù)。


      屏幕快照 2020-05-07 下午12.20.30.png
    7. .至此為止,Dealloc 的執(zhí)行流程結(jié)束。

三、weak_clear_no_lock調(diào)用流程

  1. 去掉所有指向的弱指針
  2. 調(diào)用weak_entry_remove:從區(qū)域的弱引用表中刪除條目。
/** 
 * Called by dealloc; nils out all weak pointers that point to the 
 * provided object so that they can no longer be used.
 * 
 * @param weak_table 
 * @param referent The object being deallocated. 
 */
void 
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
{
    objc_object *referent = (objc_object *)referent_id;

    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) {
        /// XXX shouldn't happen, but does with mismatched CF/objc
        //printf("XXX no entry for clear deallocating %p\n", referent);
        return;
    }

    // zero out references
    weak_referrer_t *referrers;
    size_t count;
    
    if (entry->out_of_line()) {
        referrers = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;
            }
            else if (*referrer) {
                _objc_inform("__weak variable at %p holds %p instead of %p. "
                             "This is probably incorrect use of "
                             "objc_storeWeak() and objc_loadWeak(). "
                             "Break on objc_weak_error to debug.\n", 
                             referrer, (void*)*referrer, (void*)referent);
                objc_weak_error();
            }
        }
    }
    
    weak_entry_remove(weak_table, entry);
}

那么開(kāi)發(fā)者重寫(xiě)dealloc后可以做什么,不可以做什么呢 ?

可以做什么 :

從 NotificationCenter remove observer、remove KVO, 有些非ARC管理的比如CFRelease , 有些需要流關(guān)閉,用了RAC持有disposable對(duì)象的可以dispose,這些都是比較常見(jiàn)的。還有一些會(huì) removeGestureRecognizer, addToRunLoop 的removeFromRunLoop, dispatch_release掉自己持有的queue, 不過(guò)這些可能不是必要。

不可以做:

1 . 不要調(diào)用[super dealloc],實(shí)際上想調(diào)用也調(diào)用不了。。。 ARC編譯器會(huì)自動(dòng)調(diào)用,寫(xiě)了會(huì)直接報(bào)錯(cuò)程序無(wú)法運(yùn)行;

  1. 不要使用點(diǎn)語(yǔ)法,建議使用_property 進(jìn)行存取。因?yàn)辄c(diǎn)語(yǔ)法會(huì)觸發(fā)setter 、getter方法,如果這些方法被重寫(xiě),實(shí)現(xiàn)了一些不知道的操作,可能會(huì)涉及或者觸發(fā)一些不應(yīng)該在dealloc階段做的事情比如對(duì)屬性做了KVO監(jiān)聽(tīng)。
因?yàn)檫@個(gè)方法暴露出來(lái)的目的就是為了讓開(kāi)發(fā)者來(lái)處理對(duì)象實(shí)例變量以外的資源。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,409評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,569評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,360評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,895評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,123評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,559評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,742評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,981評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,363評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,622評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,354評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,707評(píng)論 2 370