iOS weak 關(guān)鍵字漫談

weak 關(guān)鍵字的運用在 iOS 當(dāng)中屬于基礎(chǔ)知識,在面試的時候問 weak 的用處,就像兩個 iOS 程序員見面寒暄問候一樣普通了。

weak 的常見場景是在 delegate,block,NSTimer 中使用,以避免循環(huán)引用所帶來的內(nèi)存泄漏,這是教科書式的用法。

編程語言是工具,語言特性只是工具的特性,工具怎么用在于使用者。weak 關(guān)鍵字的方便之處絕不局限于避免循環(huán)引用,適當(dāng)腦洞,可以在其他場景下帶來一些有趣的應(yīng)用。

weak 的用處用一句話可歸納為:弱引用,在對象釋放后置為 nil,避免錯誤的內(nèi)存訪問。用更通俗的話來表述是:weak 可以在不增加對象的引用計數(shù)的同時,又使得指針的訪問是安全的。

weak singleton

之前見過一篇文章介紹了一個新 pattern 叫 「weak singleton」,原文出處點我。這種特殊的單例有一個有意思的特性:在所有使用該單例的對象都釋放后,單例對象本身也會自己釋放。我所見過的大部分單例使用場景,被創(chuàng)建都單例最后都會一直存活著,比如注冊登錄模塊所需要共享狀態(tài)所創(chuàng)建的 XXLoginManager,即使在用戶注冊成功進入主界面之后也不會被顯式的釋放,這在一定程度上會帶來內(nèi)存使用的浪費。所謂的「weak singleton」代碼很簡單:

+ (id)sharedInstance
{
    static __weak ASingletonClass *instance;
    ASingletonClass *strongInstance = instance;
    @synchronized(self) {
        if (strongInstance == nil) {
            strongInstance = [[[self class] alloc] init];
            instance = strongInstance;
        }
    }
    return strongInstance;
}

Controller A, B, C 都可以持有 ASingletonClass 的強引用,一旦 A,B,C 都銷毀后,ASingletonClass 的單例對象也會隨之銷毀,略巧妙不是嗎?

「weak singleton」這個漂亮名字背后其實只是簡單而巧妙的利用了 weak 特性,sharedInstance 中的 weak 就像是一個智能管家,在無人使用 instance 之后就置為 nil 銷毀,當(dāng) sharedInstance 再次被調(diào)用時,instance 又會重新被創(chuàng)建。

weak associated object

當(dāng)我們需要給已有的功能模塊添加新功能特性的時候,比如給所有的 UIViewController 添加一個 dumpViewHierarchy 方法,可以把當(dāng)前 Controller 的 view 結(jié)構(gòu)完整保存來下并上報服務(wù)器,我們有幾種思路可供選擇:

方案一:定義一個新的父類 DumpViewController,繼承該父類的子類可以獲得 dumpViewHierarchy 方法。

方案二:定義一個新的 DumpViewObject 類,已有的 Controller 只需要創(chuàng)建一個 DumpViewObject 對象,并調(diào)用 dumpViewHierarchy 方法,傳入 self 即可。

方案三:給已有的 Controller 類添加一個 Category,XXController + DumpView,并在 Category 中實現(xiàn) dumpViewController 方法,有時候我們還需要做一些狀態(tài)保存,所以擴展性更好的辦法是使用 associated object 給 Category 添加一個 DumpViewObject property,將 dumpView 相關(guān)的邏輯都寫入 DumpViewObject 類中。

方案四:使用 AOP 的方式,利用 Objective C 的 rumtime 特性 hook 每個 Controller 的 dumpViewHierarchy 方法,并在當(dāng)中實現(xiàn)相應(yīng)邏輯。

方案一,二都對已有代碼改動較大,方案四改動最小,神不知鬼不覺,dumpViewHierarchy 方法甚至可以不出現(xiàn)在 Controller 里面,但這也導(dǎo)致代碼管理上比較松散。方案三是我個人比較推崇的方式,代碼侵入少,同時方法調(diào)用邏輯也會出現(xiàn)在合適的地方,不少知名的第三方庫都使用過這種方式來添加功能,比如 facebook 開源的 FBKVOController,就通過 associated object 的方式給每個 NSObject 對象添加了一個功能屬性。

使用 associated object 的時候,有一些細(xì)節(jié)需要額外考慮。比如 property 是強引用還是弱引用,這個選擇題取決于代碼結(jié)構(gòu)的設(shè)計。如果是強引用,則對象的生命周期跟隨所依附的對象,XXController dealloc 的時候,DumpViewObject 也隨之 dealloc。如果是弱引用,則說明 DumpViewObject 對象的創(chuàng)建會銷毀由其他對象負(fù)責(zé),一般是為了避免存在循環(huán)引用,或者由于 DumpViewObject 的職責(zé)多于所依附對象的需要,DumpViewObject 有更多的狀態(tài)需要維護處理。

associated object 本身并不支持添加具備 weak 特性的 property,但我們可以通過一個小技巧來完成:

- (void)setContext:(CDDContext*)object {
    id __weak weakObject = object;
    id (^block)() = ^{ return weakObject; };
    objc_setAssociatedObject(self, @selector(context), block, OBJC_ASSOCIATION_COPY);
}

- (CDDContext*)context {
    id (^block)() = objc_getAssociatedObject(self, @selector(context));
    id curContext = (block ? block() : nil);
    return curContext;
}

添加了一個中間角色 block,再輔以 weak 關(guān)鍵字就實現(xiàn)了具備 weak 屬性的 associated object。這種做法也印證了軟件工程里一句名言「We can solve any problem by introducing an extra level of indirection」。

類似的用法還有不少,比如 NSArray,NSDictionary 中的元素引用都是強引用,但我們可以通過添加一個中間對象 WeakContainer,WeakContainer 中再通過 weak property 指向目標(biāo)元素,這樣就能簡單的實現(xiàn)一個元素弱引用的集合類。

編程語言一直處于進化當(dāng)中,語言的設(shè)計者會站在宏觀的角度,結(jié)合行業(yè)的需要,添加更多的方便特性,如果只是記住官方文檔里的幾個應(yīng)用場景,而不去思考背后的設(shè)計思路,則很難寫出有想象力的代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令偉閱讀 1,129評論 0 10
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,606評論 30 472
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,789評論 11 349
  • 一只大鴨子帶著三只小鴨子 在微波水面往來 一只兩只三只 四只五只六只七只 我在烈日里等待 孩子在考場里煎熬 201...
    靑蔥閱讀 242評論 0 0
  • 鬼天氣!沒完沒了,下了有七八天了吧。 上週二就開始下雨,早幾天晚間還能有停雨的時候,我總是候著雨?;蛴晷⌒┳グ延陚?..
    千年一眼閱讀 264評論 0 2

友情鏈接更多精彩內(nèi)容