今天無意這中遇到一個奇怪的崩潰,先上引起崩潰的代碼:
- (void)dealloc{ __weak __typeof(self)weak_self = self; NSLog(@"%@", weak_self);}當執(zhí)行到dealloc的時候,程序就crash 掉了。崩潰信息如下:
id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id){ objc_object *referent = (objc_object *)referent_id; objc_object **referrer = (objc_object **)referrer_id; if (!referent || referent->isTaggedPointer()) return referent_id; // ensure that the referenced object is viable bool deallocating; if (!referent->ISA()->hasCustomRR()) { deallocating = referent->rootIsDeallocating(); } else { BOOL (*allowsWeakReference)(objc_object *, SEL) = (BOOL(*)(objc_object *, SEL)) object_getMethodImplementation((id)referent, SEL_allowsWeakReference); if ((IMP)allowsWeakReference == _objc_msgForward) { return nil; } deallocating = ! (*allowsWeakReference)(referent, SEL_allowsWeakReference); } if (deallocating) { _objc_fatal("Cannot form weak reference to instance (%p) of " "class %s. It is possible that this object was " "over-released, or is in the PRocess of deallocation.", (void*)referent, object_getClassName((id)referent)); } // now remember it and where it is being stored weak_entry_t *entry; if ((entry = weak_entry_for_referent(weak_table, referent))) { append_referrer(entry, referrer); } else { weak_entry_t new_entry; new_entry.referent = referent; new_entry.out_of_line = 0; new_entry.inline_referrers[0] = referrer; for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) { new_entry.inline_referrers[i] = nil; } weak_grow_maybe(weak_table); weak_entry_insert(weak_table, &new_entry); } // Do not set *referrer. objc_storeWeak() requires that the // value not change. return referent_id;}可以看出,runtime 是通過檢查引用計數(shù)的個數(shù)來判斷對象是否在 deallocting, 然后通過
if (deallocating) { _objc_fatal("Cannot form weak reference to instance (%p) of " "class %s. It is possible that this object was " "over-released, or is in the process of deallocation.", (void*)referent, object_getClassName((id)referent)); }這段代碼讓程序crash。
再看一下 _objc_fatal 這個函數(shù)
void _objc_fatal(const char *fmt, ...){ va_list ap; char *buf1; char *buf2; va_start(ap,fmt); vasprintf(&buf1, fmt, ap); va_end (ap); asprintf(&buf2, "objc[%d]: %s/n", getpid(), buf1); _objc_syslog(buf2); _objc_crashlog(buf2); _objc_trap();}可以看到這個函數(shù)實際會在控制臺輸出一段信息,然后調(diào)用 _bojc_trap() 引起 crash. 而最后一個函數(shù)調(diào)用剛好也對上我們之前的崩潰堆棧。
新聞熱點
疑難解答