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

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];
}

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.

What is a "non-weak zeroing reference"

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/

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.

NSString being released even after being retained

I have an NSString that I've retained, and the only place I release it is in the dealloc method. For some reason, however, later in the program when I try to reference it (its length, specifically), I get a crash, saying [CFString length]:message sent to deallocated instance 0xff32c50.
I explicitly retain the string earlier in the program. Is there any reason why this would be happening? Any help is appreciated.
The string, entityParameter, is declared in the header, and defined later.
Here is some of the code:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
The place where I'm getting the crash looks like this:
if([entityParameter length] != 0 && entityParameter != nil)
{
return;
}
I have an NSString that I've retained,
and the only place I release it is in
the dealloc method. For some reason,
however, later in the program when I
try to reference it (its length,
specifically), I get a crash, saying
[CFString length]:message sent to
deallocated instance 0xff32c50.
Obviously, it isn't retained, then.
If by "retained" you mean "assigned to a property", are you doing:
self.prop = [NSString ...];
Or:
prop = [NSString ...];
Because the former will retain (if the property is declared as retain) whereas the latter will not. Note that NSString properties should generally be declared copy, but that is orthogonal to the question).
If your code is as written:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
And you really do only release it in dealloc, then make sure your containing object hasn't already been deallocated. That may be happening. Or it might be that you've leaked the string reference somewhere and spuriously deleted it without a retain.
Using Zombie detection in instruments with "track retain/release events" (or whatever it is called) should show you every last retain/release event on the object, including the one the blew up.

Objective-C Difference between setting nil and releasing

I've learned that in dealloc you do [object release]; but in viewDidUnload (in a UIViewController subclass) you do self.object = nil. What is really the difference because self.object = nil (we're assuming object is a (nonatomic, retain) property) retains nil (which does nothing) and then releases the old value and then the reference count is 0 right?
self.object = nil calls your setter, which will release the old value, set the member to nil, and possibly do other things (it's a method, so it could do anything). The "anything" part of that is potentially dangerous; see this question, for example.
[object release] releases the old value, but leaves the member as a now-dangling pointer, which is a good recipe for bugs. In dealloc it doesn't really matter, since the pointer itself is about to go away too, but in any other case it's a very bad idea to release a member without setting it to nil.
(As a sidenote, you should never assume that releasing an object gives it a reference count of 0. It releases your reference, but other objects may still have references to it.)
If you do object = nil without [object release], that might causes memory leaking. If you do [object release] without object = nil afterwards, object becomes dangling pointer as #Jim suggested. self.object = nil is a sugar for setter function call.
If you just release an object, then it will become freed object.
And if you try to perform any sort of operation on freed object then your app crashes. To avoid such accidents, it is always preferred "assign your object to nil after releasing it". Because we all know any operations performed on nil will not be executed :)
If you do [object release], and want to access the object the app simply crash.
If you do object = nil, and want to access the object nothing will perform.
The reason is in the [object release], you are attempted to free the object. so its dont have any pointer (no memoty).In the object = nil, you are attempted to assign the object with null pointer. so if u trying to access the object nothing will happen.
Generally we wrote the code as [object release]; object = nil; because if u access the object unexpectedly, the app wont crashed.