OC Runtime之Weak(3)---探究NSObject
Runtime對於weak_table_t還有一層封裝,也就是SideTable。這層封裝對於弱引用機制的主要目的是解決執行緒安全的問題,因為之前也提到weak_table_t的各種操作並不是執行緒安全的。
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
SideTable() {
memset(&weak_table, 0, sizeof(weak_table));
}
~SideTable() {
_objc_fatal("Do not delete SideTable.");
}
void lock() { slock.lock(); }
void unlock() { slock.unlock(); }
void forceReset() { slock.forceReset(); }
// Address-ordered lock discipline for a pair of side tables.
template<HaveOld, HaveNew>
static void lockTwo(SideTable *lock1, SideTable *lock2);
template<HaveOld, HaveNew>
static void unlockTwo(SideTable *lock1, SideTable *lock2);
};
RefcountMap用於OC的引用計數機制,此處不表。slock實際上是os_unfair_lock_s型別,用於處理執行緒安全的問題。SideTable提供的方法都與鎖有關。
NSObject的實現中和弱引用相關的的最重要的函式就是storeWeak,其實現如下:
template <HaveOld haveOld, HaveNew haveNew,
CrashIfDeallocating crashIfDeallocating>
static id
storeWeak(id *location, objc_object *newObj)
{
assert(haveOld || haveNew);
if (!haveNew) assert(newObj == nil);
Class previouslyInitializedClass = nil;
id oldObj;
SideTable *oldTable;
SideTable *newTable;
// Acquire locks for old and new values.
// Order by lock address to prevent lock ordering problems.
// Retry if the old value changes underneath us.
retry:
if (haveOld) {
oldObj = *location;
oldTable = &SideTables()[oldObj];
} else {
oldTable = nil;
}
if (haveNew) {
newTable = &SideTables()[newObj];
} else {
newTable = nil;
}
SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);
if (haveOld && *location != oldObj) {
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
goto retry;
}
// Prevent a deadlock between the weak reference machinery
// and the +initialize machinery by ensuring that no
// weakly-referenced object has an un-+initialized isa.
if (haveNew && newObj) {
Class cls = newObj->getIsa();
if (cls != previouslyInitializedClass &&
!((objc_class *)cls)->isInitialized())
{
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
_class_initialize(_class_getNonMetaClass(cls, (id)newObj));
// If this class is finished with +initialize then we're good.
// If this class is still running +initialize on this thread
// (i.e. +initialize called storeWeak on an instance of itself)
// then we may proceed but it will appear initializing and
// not yet initialized to the check above.
// Instead set previouslyInitializedClass to recognize it on retry.
previouslyInitializedClass = cls;
goto retry;
}
}
// Clean up old value, if any.
if (haveOld) {
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
// Assign new value, if any.
if (haveNew) {
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating);
// weak_register_no_lock returns nil if weak store should be rejected
// Set is-weakly-referenced bit in refcount table.
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}
// Do not set *location anywhere else. That would introduce a race.
*location = (id)newObj;
}
else {
// No new value. The storage is not changed.
}
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
return (id)newObj;
}
首先請忽視C++奇怪的各種語法,比如為什麼template中的列舉會跑到引數裡去(手動哭泣)。haveOld和haveNew主要用來控制具體的操作,比如給一個物件新增一個弱引用,或者是刪除一個弱引用。函式的前半部分主要在處理執行緒安全和類載入的問題,和弱引用的邏輯關係不大。我們從 if (haveOld) { 這一行看起,如果haveOld是true,則說明引數裡的弱引用已經指向了一個物件,需要呼叫weak_unregister_no_lock方法解除關聯。如果haveNew是true,則呼叫weak_register_no_lock關聯目標物件和弱應用,並且將弱引用設定為指向目標物件。因此通過設定haveOld和haveNew不同的組合,可以控制該函式完成不同的操作。
純邏輯來看,這一部分相對簡單,但考慮到執行緒安全,類的初始化,Tagged Pointer等等細節,要處理的地方還是非常多。這一系列的文章主要介紹了弱引用機制的實現,幫助大家對弱引用有一個更詳細更立體的理解,未涉及到太多的具體的底層技術細節,如果讀者有興趣的話,可以繼續深入探究。後續的runtime相關的文章也可能會繼續提及。
相關文章
- Runtime面試之weak面試
- Object Runtime -- WeakObject
- OC 看objc原始碼認識weakOBJ原始碼
- OC load、initialize、一些NSObject方法Object
- iOS底層學習 - 記憶體管理之weak原理探究iOS記憶體
- iOS底層原理探究- NSObject 所佔記憶體iOSObject記憶體
- iOS底層原理探究-RuntimeiOS
- iOS開發 Runtime是如何實現weak屬性的?iOS
- 【OC刨根問底】-Runtime簡單粗暴理解
- iOS開發之OC篇(3)—— NSArray、NSMutableArrayiOS
- iOS 從原始碼深入探究weak的實現 | 掘金技術徵文iOS原始碼
- 結合 category 工作原理分析 OC2.0 中的 runtimeGo
- iOS 多執行緒之NSThread和NSObjectiOS執行緒threadObject
- 窺探NSObjectObject
- 1. NSObjectObject
- ObjC之RunTime(下)OBJ
- ObjC之RunTime(上)OBJ
- Swift 記憶體管理之 weak 與 unownedSwift記憶體
- 由 NSObject *obj = [[NSObject alloc] init] 引發的一二事兒Object
- iOS 防止Crash之runtimeiOS
- HttpContext探究之RequestServicesHTTPContext
- Swift之你真的知道為什麼使用weak嗎?Swift
- 知識點:id 和NSObject *對比,以及id <NSObject>介紹Object
- Runtime底層原理探究(二) --- 訊息傳送機制(慢速查詢)
- Runtime底層原理探究(一) --- 訊息轉發機制(快速轉發)
- NSObject class和NSObject protocol的關係(抽象基類與協議)ObjectProtocol抽象協議
- iOS開發之runtime(一):runtime除錯環境搭建iOS除錯
- id 和 NSObject區別Object
- iOS __weak、__block使用iOSBloC
- weak實現原理
- iOS之Wifi開發探究iOSWiFi
- mysql探究之null與not nullMySqlNull
- OC多型 - OC多型
- Runtime底層原理探究(三) --- 訊息轉發機制(動態方法解析)
- iOS之runtime詳解api(一)iOSAPI
- iOS之runtime詳解api(三)iOSAPI
- iOS之runtime詳解api(二)iOSAPI
- iOS之runtime詳解api(四)iOSAPI