首页 > 学院 > 开发设计 > 正文

Dealloc 时取 weak self 引起崩溃

2019-11-09 16:22:49
字体:
来源:转载
供稿:网友

今天无意这中遇到一个奇怪的崩溃,先上引起崩溃的代码:

- (void)dealloc{ __weak __typeof(self)weak_self = self; NSLog(@"%@", weak_self);}

当执行到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 是通过检查引用计数的个数来判断对象是否在 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 这个函数

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();}

可以看到这个函数实际会在控制台输出一段信息,然后调用 _bojc_trap() 引起 crash. 而最后一个函数调用刚好也对上我们之前的崩溃堆栈。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表