問題
weak 變量在引用計數為0時,會被自動設置成 nil,這個特性是如何實現的?
答案
在 Friday QA 上,有一期專門介紹 weak 的實現原理。https://mikeash.com/pyblog/friday-qa-2010-07-16-zeroing-weak-references-in-objective-c.html
《Objective-C高級編程》一書中也介紹了相關的內容。
簡單來說,系統有一個全局的 CFMutableDictionary
實例,來保存每個對象的 weak 指針列表,因為每個對象可能有多個 weak 指針,所以這個實例的值是 CFMutableSet
類型。
剩下我們要做的,就是在引用計數變成 0 的時候,去這個全局的字典里面,找到所有的 weak 指針,將其值設置成 nil。如何做到這一點呢?Friday QA 上介紹了一種類似 KVO 實現的方式。當對象存在 weak 指針時,我們可以將這個實例指向一個新創建的子類,然后修改這個子類的 release 方法,在 release 方法中,去從全局的 CFMutableDictionary
字典中找到所有的 weak 對象,並且設置成 nil。我摘抄了 Friday QA 上的實現的核心代碼,如下:
Class subclass = objc_allocateClassPair(class, newNameC, 0); Method release = class_getInstanceMethod(class, @selector(release)); Method dealloc = class_getInstanceMethod(class, @selector(dealloc)); class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release)); class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc)); objc_registerClassPair(subclass);
當然,這並不代表蘋果官方是這么實現的,因為蘋果的這部分代碼並沒有開源。《Objective-C高級編程》一書中介紹了 GNUStep 項目中的開源代碼,思想也是類似的。所以我認為雖然實現細節會有差異,但是大致的實現思路應該差別不大。
全文完。
下一期的面試題:
我們知道,從 Storyboard 往編譯器拖出來的 UI 控件的屬性是 weak 的,如下所示:
@property (weak, nonatomic)
IBOutlet UIButton *myButton;
那么,如果有一些 UI 控件我們要用代碼的方式來創建,那么它應該用 weak 還是 strong 呢?為什么?