What is a "non-weak zeroing reference" - objective-c

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?

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.

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/

Related

Send the message objc_msgSend(class,#selector(dealloc)) to release the object, why is it wrong to access the object pointer?

The code is under ARC. When I delete the code NSObject* objc = (NSObject*)object; the program runs fine, but I didn't have access to the pointer objc. When I keep the code NSObject* objc = (NSObject*)object; I am prompted EXC_BAD_ACCESS (code=1, address=0x20). Is the system accessing the objc pointer after the block function body ends?
-(void)resetDeallocMethodWithInstance:(NSObject*)obj
{
Class targetClass = obj.class;
#synchronized (swizzledClasses()) {
NSString *className = NSStringFromClass(obj.class);
if ([swizzledClasses() containsObject:className]) return;
SEL deallocSel = sel_registerName("dealloc");
__block void (*deallocBlock)(__unsafe_unretained id, SEL) = NULL;
id block = ^(__unsafe_unretained id object){
NSObject* objc = (NSObject*)object;
NSUInteger hash = ((NSObject*)object).hash;
[self removeAllTargetWitSuffixKey:[NSString stringWithFormat:#"%lu",(unsigned long)hash]];
if (deallocBlock == NULL) {
struct objc_super superInfo = {
.receiver = object,
.super_class = class_getSuperclass(targetClass)
};
void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
msgSend(&superInfo, deallocSel);
} else {
deallocBlock(object, deallocSel);
}
};
IMP blockImp = imp_implementationWithBlock(block);
if (!class_addMethod(obj.class, deallocSel, blockImp, "v#:")) {
Method deallocMethod = class_getInstanceMethod(obj.class, deallocSel);
deallocBlock = (__typeof__(deallocBlock))method_getImplementation(deallocMethod);
deallocBlock = (__typeof__(deallocBlock))method_setImplementation(deallocMethod, blockImp);
}
[swizzledClasses() addObject:className];
}
return;
}
enter image description here
Note: This answer is being directly typed in, your code has not been tested, indeed no code has been tested. Therefore that the issues below are causing your issues is being inferred.
There area number of issues with your design:
Swizzling dealloc is not recommended. The dealloc method is called automatically by the system when it is in the process of destroying an object, as such using the partly destroyed object inappropriately (whatever that might be) could lead to issues - as you have found!
You are using ARC under which "an implementation of dealloc, [should] not invoke the superclass’s implementation". However your block does this.
The variable objc is unused. However by default a local variable has the attribute strong so you are creating a strong reference to an object in the process of destruction. Any strong reference made by the block in this way will be released by ARC when the block has finished, this is almost certainly not good as your error indicates.
You appear to be trying to call your removeAllTargetWithSuffixKey: method when a particular object is destroyed (appear as you swizzle [and can only swizzle] the class but are using the hash of a particular object). A better way to do this avoiding swizzling is to use associated objects.
The runtime function objc_setassociatedobject() allows you to attach an object to a particular instance of another object and have that object be destroyed automatically when its host is destroyed (use an objc_AssociationPolicy of OBJC_ASSOCIATION_RETAIN).
Design a class which has an instance property of your required hash value and a dealloc method which calls your removeAllTargetWithSuffixKey: then rather than swizzle the class simply create and associate an instance of your class with the target object.
HTH
Yes, it's accessing the pointer after the method ends. If this is being compiled under ARC, then the objc is a "strong" reference. However, you are fabricating the implementation of the dealloc method, and so are retaining the object when it's already going to be dealloced, so it's too late to have a strong reference to it. Your implementation is going to call super, which should actually deallocate the object, and then afterwards ARC is going to release the objc value, but it's already gone since it's the receiver, i.e. "self" if you were writing a normal dealloc method.
ARC will never retain self in a regular dealloc method, but that is what you are effectively doing. The "object" value is the same pointer, but is explicitly __unsafe_unretained, so you should just use that directly. You can type the block as NSObject* instead of id if that helps, but it shouldn't matter. Or you can make your objc value also __unsafe_unretained so ARC leaves it alone. You don't want ARC touching the "self" value inside the block in any way, since you are going around ARC's back in this case.
Whatever the case, once you are in an object's dealloc method, don't ever retain/release/autorelease the self pointer -- it will end up with crashes. Calling a method from dealloc and passing a reference to self is a no-no, for example. You need to be very careful about that, and understand exactly what ARC is doing if you are playing these types of runtime games.

Objective-C: Should we use weak self within block or assign weak self to strong before using it?

As we know, using strong self within a block can lead to retain cycles and memory leak. Is the common practice to use weak self in a block, or is it better to assign the weak self to strong within the block and then use it as such so the weak self is not released during block execution? Does it matter since weak self will be zero-ed out anyway?
Due to the volatile nature of weak variables, you should use them with care. If you are using weak variables in a multithreading environment, it is considered good practice to assign the weak variable to a strong one and check for nil before using. This will ensure that the object will not be released in the middle of your method, causing unexpected results.
Consider the following case:
__weak id var;
//...
if(var != nil)
{
//var was released here on another thread and there are not more retaining references.
[anotherObj performActionWithAnObjThatMustNotBeNil:var]; //<- You may crash here.
}
The compiler can be configured to throw a warning on a consecutive access of a weak variable.
On the other hand, if your use is in the main thread, and all calls to the object are on the main thread, this problem is moot, since the object will either be released before the block call or after, thus it being safe to access the weak variable directly.
There are two possible questions here that are easy to get confused:
Is it possible for a __weak reference to become nil in the middle of a method?
id __strong strongObject = ...;
id __weak weakObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
[weakObject method1]; // if weakObject is non-nil here
[weakObject method2]; // can it become non-nil here?
});
Yes! Xcode will even warn you about it.
Is it possible for self to become nil in the middle of a method if the method is called on a __weak lvalue as below?
id __strong strongObject = ...;
id __weak weakObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
// is it possible for weakObject to be deallocated
// while methodUsingSelf is being called?
[weakObject methodUsingSelf];
});
- (void)methodUsingSelf {
NSLog(#"%#", self); // Could this be non-nil
NSLog(#"%#", self); // while this is nil?
}
No! Joe Groff, of the Swift team at Apple, said so:
self is guaranteed kept alive by ObjC ARC while a method on self is
executing.
Clang's official ARC documentation covers this case in the Semantics/Reading subsection:
Reading occurs when performing a lvalue-to-rvalue conversion on an
object lvalue.
For __weak objects, the current pointee is retained and then released
at the end of the current full-expression. This must execute
atomically with respect to assignments and to the final release of the
pointee.
Thus, calling a method on a __weak variable, is roughly equivalent to the following Manual Retain/Release (MRR) code:
id retainedObject = ...;
id assignedObject = strongObject;
dispatch_async(dispatch_get_main_queue(), ^{
{
[assignedObject retain];
[assignedObject methodUsingSelf];
[assignedObject release];
}
});
Of course, in MRR, [assignedObject retain]; might crash because the object assignedObject points to might have been deallocated, so assignedObject might point to garbage. ARC doesn't have this problem because it zeroes weak references.
I think that even if using the weak will work and be retained as long as needed, assigning it to strong before using will make it more readable and "worries free"...:
__weak id weakThing = thing;
thing.someBlock = ^{
if (weakThing) {
id strongThing = weakThing;
strongThing doThisWithThat...
}
};
Compiler won't complain and it is safe and maybe not less importantly - easy to understand for John Doe who will try to read this code tomorrow....
You can continue to use the weak self. The only time you'd need to use strong self is if you are trying to access a self->ivar directly, instead of going through a property.

How can the Objective-C runtime know whether a weakly referenced object is still alive?

With the advent of ARC, some new functions were made available to allow developers to play around with weakly referenced objects. id objc_loadWeak(id *location) is one of them. This function receives one parameter correspoding to a location in memory where a weak object was stored and returns this object if it is still alive or nil if it were deallocated.
It seems that when an object obj is stored as weak in a location location with id objc_storeWeak(id *location, id obj), obj is put in a "weak map", with location as a key. However, in order to retrieve obj, objc_loadWeak can not only use location as a key and return the value, which corresponds to obj. It must also check whether obj is still alive to return nil if it is not anymore.
However, objc_loadWeak can not try to read the object's retain count, because the object may have been deallocated. Moreover, although the weak map, objc_storeWeak, objc_loadWeak and the NSObject class are implemented in the same file (NSObject.mm), NSObject's dealloc method doesn't signals to the weak map that the object that is being deallocated is going away.
So, how does the Objective-C runtime figure out whether a weak object is still alive?
NSObject's dealloc method doesn't signals to the weak map that the object that is being deallocated is going away.
It does.
- [NSObject dealloc]
calls
_objc_rootDealloc(self);
which in turn invokes
object_dispose()
which in turn calls
objc_destructInstance()
which finally calls
objc_clear_deallocating()
This last function looks like this:
void
objc_clear_deallocating(id obj)
{
assert(obj);
assert(!UseGC);
SideTable *table = SideTable::tableForPointer(obj); /* *** THIS LINE *** */
// clear any weak table items
// clear extra retain count and deallocating bit
// (fixme warn or abort if extra retain count == 0 ?)
OSSpinLockLock(&table->slock);
if (seen_weak_refs) {
arr_clear_deallocating(&table->weak_table, obj); /* *** THIS LINE *** */
}
table->refcnts.erase(DISGUISE(obj)); /* *** THIS LINE *** */
OSSpinLockUnlock(&table->slock);
}
The three highlighted lines do the magic. SideTable is a C++ class implemented in NSObject.mm of which the refcnts member variable does exactly what it sounds like it does: it holds reference counts.

Can an Objective-C object be deallocated while an instance method is being invoked on it?

Consider the following: An instance of an Objective-C class is referenced by one strong reference and one weak reference (under ARC). On thread X, a method is called on the instance via the weak reference. On thread Y, the strong reference is broken such that there are no more strong references to the instance, and it should be deallocated.
Is this situation possible, in that the object might be deallocated on thread Y while the method is executing on thread X? Similarly, does invoking a method on an object 'retain' that object until the method returns?
ARC actually does retain weak references before calling instance methods on them, and releases after the call.
I was researching this issue and was corrected by a colleague after showing him this stackoverflow question. He pointed to this:
http://lists.apple.com/archives/objc-language/2012/Aug/msg00027.html
Sure enough, in the assembly, ARC retains and releases around an invocation on a weak reference.
One time you will want to listen to CLANG_WARN_OBJC_RECEIVER_WEAK is for nil checks, when nil could cause an error.
if (self.weakRefToParent) {
//self.weakRefToParent could be dealloced and set to nil at this line
NSString *name = [self.weakRefToParent name]; //CLANG_WARN_OBJC_RECEIVER_WEAK warning
[self.namesArray addObject:name]; //name is nil, NSInvalidArgumentException
}
This is the safer way:
Parent *strongRefToParent = self.weakRefToParent;
if (strongRefToParent) {
NSString *name = [strongRefToParent name];
[self.namesArray addObject:name];
}

ARC, ivars in Blocks and Reference Cycles via Captured Self

I’m working in a pure iOS5/ARC environment, so I can use __weak references as needed. I do reference ivars in a block in many situations, most notably, animation blocks that move views around, which are properties of say, my view controller class.
My question:
In the most trivial use of ivars in a block, am I creating a reference cycle? Do I need to use the __weak self / strong self technique everytime I write a block that manipulates instance variables of the containing object?
I’ve been re-watching the 2011 WWDC Session #322 (Objective-C Advancements in Depth) to understand the nuances regarding the 3 minute segment starting at time index 25:03 about “Reference Cycle Via Captured Self”. To me, this implies any usage of ivars in a block should be safeguarded with the weak self / strong self setup as described in that segment.
The sample method below on a view controller, is typical of animations I do.
In the openIris block, is it wrong to reference ivars “_topView” and “_bottomView” as I have?
Should I always setup a __weak reference to self before the block, then a strong reference inside the block to the weak reference just setup prior, and then access the ivars through that strong reference within my block?
From the WWDC session, I understand that referencing ivars in a block is really creating a reference to the implied self that these ivars hang off of.
To me, this implies that there really isn’t any simple or trivial case where it is correct to access ivars in a block without the weak/strong dance to ensure no cycles. Or am I reading to much into a corner case that doesn’t apply to simple cases, such as my example?
- (void)openIrisAnimated:(BOOL)animated
{
if (_isIrisOpened) {
NSLog(#"Asked to open an already open iris.");
return; // Bail
}
// Put the common work into a block.
// Note: “_topView” and “_bottomView” are the backing ivars of
// properties “topView” and “bottomView”
void (^openIris)() = ^{
_topView.frame = CGRectMake(....);
_bottomView.frame = CGRectMake(....);
};
// Now do the actual opening of the iris, whether animated or not:
if (animated) {
[UIView animateWithDuration:0.70f
animations:^{
openIris();
}];
}
else {
openIris();
}
_irisOpened = YES; // Because we have now just opened it
}
Here’s how I’d re-write the openIris block piece using the guidance from Session #322, but I’m just wondering if all my similar blocks require this weak/strong reference dance to ensure correctness and stability:
__weak MyClass *weakSelf = self;
void (^openIris)() = ^{
MyClass *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.topView.frame = CGRectMake(....);
strongSelf.bottomView.frame = CGRectMake(....);
}
};
Is this in fact, necessary?
There is only a cycle here if self then goes on to hold a reference to the block (or something owned by self). If not you're good to go as the lifetime of the block is not dictated by the self it retained.
So in your particular example, you seem to be in the clear. Animation blocks don't need to participate in the weak/strong self dance.
The case to worry about is something like addObserverForName:object:queue:usingBlock:. The docs say, "The block is copied by the notification center." Under ARC, that word "copy" is a red flag; now you need to take steps so that you (the caller) will not leak.
EDIT: Also, sometimes ARC itself will alert you. The completion block of -[UIPageViewController setViewControllers:direction:animated:completion:] is a case in point. I would never have suspected that using self here might cause a retain cycle, but ARC warned that it would, so I did the weak-strong dance just in case.