In Clang's Objective-C Automatic Reference Counting we see the following
For __weak objects, the lvalue is updated to point to the new pointee, unless the new pointee is an object currently undergoing deallocation, in which case the lvalue is updated to a null pointer. This must execute atomically with respect to other assignments to the object, to reads from the object, and to the final release of the new pointee.
In objc-weak.mm wee see the following chunk of code in weak_register_no_lock()
:
if (deallocating) {
if (crashIfDeallocating) {
_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));
} else {
return nil;
}
}
I set a breakpoint in my UIViewController subclass dealloc
method and tried invoking [self allowsWeakReference]
in lldb which resulted in NO
value.
If we try to set self to weak property of another object the app will crash in accordance with the objc-weak.mm code.
The question is – why does this happen? Is the clang's specification wrong? Is is this a bug in objc implementation?
Here is a simple piece of code that will reproduce the crash:
//cc -fmodules -fobjc-arc -g crash.m -o crash
@import Foundation;
@interface Foo : NSObject
@end
@implementation Foo
- (void)dealloc {
Foo * __weak weakSelf = self; // crashes on this line
}
@end
int main() {
(void)[[Foo alloc] init];
return 0;
}
self
to weak properties during the deallocation, but now I see that it isn't. Isn't it a bug? – CongocrashIfDeallocating
? – Versicularfalse
most/all of the time. You'd have to do further tracing in the source code to actually see what affects it. – VersicularsomeObject.delegate = self
in thedealloc
method, then I'm setting a pointer to an object that is currently undergoing deallocation. – CongoNSObject.mm
, you can see thatobjc_initWeak
andobjc_storeWeak
pass crash = true, and there are also functions calledobjc_initWeakOrNil
andobjc_storeWeakOrNil
that don't crash. I agree that this contradicts the ARC spec, where in the section for runtime functions at the end it explicitly says thatobjc_initWeak
andobjc_storeWeak
are to store a null pointer if the pointee is undergoing deallocation. – Freezedryobjc_initWeak
andobjc_storeWeak
, and they don't crash. – Freezedryweak_register_no_lock
that it always crashes when deallocating. – Freezedry