What is a "non-weak zeroing reference"

465 views Asked by At

In the OS X v10.11 beta release notes, I find the following:

NSNotificationCenter and NSDistributedNotificationCenter no longer send notifications to registered observers that may be deallocated. If the observer is able to be stored as a zeroing-weak reference the underlying storage stores the observer as a zeroing weak reference. Alternatively, if the object cannot be stored weakly (because it has a custom retain/release mechanism that would prevent the runtime from being able to store the object weakly) the object is stored as a non-weak zeroing reference. This means that observers are not required to un-register in their deallocation method. [emphasis mine]

This doesn't make sense to me. If it is a non-weak reference, wouldn't it be a strong reference, then? So the NSNotificationCenter would still be an owner, so the object wouldn't deallocate (until manually unregistered), so it's nonsensical in this context to say it's "zeroing".

If this is referring to a sort of __unsafe_unretained reference, then the question is…how then would NSNotificationCenter avoid messaging a zombie?

2

There are 2 answers

2
Richard J. Ross III On BEST ANSWER

The answer for this lies deep within the objective-c runtime, and how __weak variables actually work. To explain, let's look a little bit at objc_weak.mm:

id 
weak_read_no_lock(weak_table_t *weak_table, id *referrer_id) 
{
    ...

    if (! referent->ISA()->hasCustomRR()) {
        if (! referent->rootTryRetain()) {
            return nil;
        }
    }
    else {
        BOOL (*tryRetain)(objc_object *, SEL) = (BOOL(*)(objc_object *, SEL))
            object_getMethodImplementation((id)referent, 
                                           SEL_retainWeakReference);
        if ((IMP)tryRetain == _objc_msgForward) {
            return nil;
        }
        if (! (*tryRetain)(referent, SEL_retainWeakReference)) {
            return nil;
        }
    }

    return (id)referent;
}

As you can see, when custom -retain and -release methods are used by an object, it's not guaranteed that they support weak references at all (also note that you can use an entirely different object for an object's weak references, though that's a topic for another time).

This is because weak references are cleaned up by objc_destructInstance, which calls objc_clearDeallocating, which calls weak_clear_no_lock.

Now, objc_destructInstance is NOT required to be called by custom object implementations, although most objects will call it.

Thus, the runtime allows you to implement the method -allowsWeakReference (and retainWeakReference) to disable weak references to your object, in which case it's most likely zero'd out by swizzling -dealloc on the object. Of course, this is all implementation details, so NSNotificationCenter could have it's own innovative way of doing things, but that's my best guess without attempting to disassemble NSNotificationCenter.

2
Proton On

Declaring a property as strong makes that property a strong reference. Declaring it as weak uses a zeroing weak reference. The unsafe_unretained modifier uses a non-zeroing weak reference

Briefly: non-weak zeroing reference == unsafe_unretained refernce

Reference:

https://mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html http://www.jessesquires.com/UIKit-changes-in-iOS-9/