Asynchronous methods called inside `-dealloc` could generate unwanted zombie objects - ios

As I was walking through some line of codes I stumbled upon this problem a couple of days ago,
- (void)dealloc {
...
[self.postOfficeService deregister:self];
...
}
Where the de-registration from the Post Office Service is an asynchronous operation, even if it's not self evident from the interface as there's no block or function passed to the postOfficeService.
The internal implementation of postOfficeService's -deregister method is something like that
// -deregister:(id)formerSubscriber implementation
//some trivial checks here
// deregister former subscriber
dispatch_asynch(_serialQueue, ^{
[self.subcribers removeObject:formerSubscriber];
});
...
The container, self.subscribers, does perfectly its job and contains only weak references. I.e. it is a NSHashTable.
As long as the deregistration method got called within the dealloc method, I keep on getting a crash while postOfficeService is trying to remove the former subscribers from its list inside that asynch block, which is used for thread safety purposes I guess.
Adding a breakpoint on [self.subscribers removeObject:formerSubscriber], it's possible to notice that the formerSubscriber object is always a NSZombieObject. That's the reason for crashes.
I know that it's possible to get thread safety for deregister method without incurring in this problem - I figure it should be enough use the dispatch_synch in lieu of the dispatch_asynch version
I think this is one of the reason why asynchronous methods shouldn't be called within dealloc methods.
But the question is how's possible to constantly get NSZombie objects even if we are in an ARC environment and the container objects is a NSHashTable (so it should be working I guess)?

The rule is: When dealloc is called, the object will be gone once dealloc returns to its caller (whoever called release when the reference count was 0), and nothing is going to prevent this.
Before ARC, you might have tried to retain an object inside dealloc - doesn't help; once dealloc is called the object will go (and dealloc will be called only once for it, in case you do a retain / release inside dealloc). ARC does the same, just automatically.

Using ARC doesn't means all your memory problem magically disappeared.
What happened is
[obj release] called by ARC
[obj dealloc]
[obj.postOfficeService deregister:obj]
[obj retain] - sorry you can't cancel the deallocation process
dispatch_async
free(obj) - from this point, obj is a zombie
GCD scheduling tasks
dispatch_async execute task
use obj - crash
The correct solution is use dispatch_sync to make sure you not trying to use object after it is deallocated. (be careful about dead lock)

Don't call asynchronous cleanup methods from dealloc. It's just not a good idea. Your -deregister should be synchronous.
NSHashTable stores pointers - it's the equivalent of __unsafe_unretained or assign - UNLESS it was created using +weakObjectsHashTable or the equivalent set of options (NSHashTableZeroingWeakMemory and NSPointerFunctionsObjectPersonality). If it was not created that way, it is quite likely you will have values pointing to zombie objects.
The question of "why am I getting zombies" is best answered by profiling your application with the Zombies template in Instruments and stimulating the required behavior.

I agree with the others that you should probably avoid asynchronous cleanup in your -dealloc method. However, it may be possible to fix this by making the parameter to -deregister: __unsafe_unretained. That method would then have to treat the pointer purely as a opaque value. It must not dereference it or message it. Unfortunately, you don't control the implementation of NSHashTable and can't guarantee that. Even if NSHashTable could be relied upon, the interface of -removeObject: takes an implicitly strong object pointer, so ARC might retain the pointer when it's copied from the unsafe unretained pointer.
You might use the C function API for hash tables (e.g. NSHashRemove()) as suggested in the overview for the NSHashTable class.

Related

Can an object be deallocated during method execution?

Let's assume that we create an instance of class var foo: Foo? = Foo() on the main thread and we call some time consuming instance method bar of Foo on another thread, after a short time we set foo to nil on main thread. What happens with the execution of bar, in my understanding bar should still continue its execution since invoking instance method implicitly passes self as the first argument, so even those the last explicit ref to foo was broken we still have a ref inside of a method and it should be good. But then I found this stackoverflow post which completely breaks my understanding. So, can somebody confirm/deny the fact that object cannot be deallocated during its method execution
Short answer is that your belief is correct, and you're looking at a question that's not relevant to Swift.
Your link is to non-ARC Objective-C. Swift always uses ARC, and ARC is very conservative about retains. Consider the following Objective-C call:
[target runMethod: parameter];
Under ARC, this is (conceptually) transformed into:
[target retain];
[parameter retain];
[target runMethod: parameter];
[parameter release];
[target release];
retain and release are atomic, thread-safe calls.
A similar behavior exists in Swift. Because of this, as a general rule (in the absence of Unsafe), a variable cannot "disappear" while you'll holding onto it.
This is the implementation detail. The better way to think about it is that by default variables and parameters are strong, and an object cannot be destroyed while there is a strong reference. This matches your understanding.
Prior to ARC, though, you needed to insert extra retains and releases yourself to protect against this kind of situation, and it was very common not to. (Prior to 10.6, most ObjC was single-threaded.)
Even without threads, there are ways this can go astray without ARC. Since callers often didn't immediately retain returned values if they only needed them temporarily, it was possible to get dangling pointers even without multiple threads. For example, with a trivial accessor with no memory management, this can crash:
NSString *name = [person name];
[person release];
[self doSomethingWithName: name];
This is why you often see old ObjC getters written in the form:
- (NSString*) title {
return [[title retain] autorelease];
}
This made sure that the returned value would survive until the end of the event loop even if self released it or self was deallocated.
Swift does similar things via ARC, but as the name suggests, it's all automatic.

Why am I crashing when trying to create a weak reference to self while dealloc is happening on another thread?

Background
Our app has a class that attempts to implement the Receptionist Pattern for KVO observation. Other classes throughout the app (such as view controllers) create instances of this one Receptionist class to serve as the KVO observer. Each Receptionist instance keeps a copy of a block provided by the owner, which the Receptionist instance will invoke on the proper operation queue when a KVO notification arrives.
The Receptionist's dealloc method invokes the KVO removeObserver method. The Owner keeps the Receptionist instance as a strong-reference field, so when the Owner is deallocated, the Receptionist will remove itself as an observer in the process of being deallocated.
The Crash
We're seeing reports from the field of crashes when the KVO notification is received by a Receptionist instance on one thread while the same instance's dealloc is in progress on another thread. The Receptionist's implementation of observeValueForKeyPath:ofObject:change:context: is crashing on this line:
__weak typeof(self) weakSelf = self;
The stack trace in the crash report shows this as a call to objc_initWeak, which calls weak_register_no_lock, which calls _objc_fatal.
The object whose key is being observed by this particular Receptionist is never deallocated. The Owner is also not being deallocated; the Owner is replacing this Receptionist instance with a different one.
The Confusion
I can understand that it's not useful to create a weak reference to an object that's already being deallocated, but I would expect weakSelf to receive a nil value, not to cause a crash.
The documentation for objc_initWeak explicitly mentions setting the target to null if the argument to which the reference is desired has begun deallocation. That sounds like the desired behavior, but I don't think it's what I'm seeing. I'm not keen to replace that line with an explicit call to objc_initWeak, since I doubt I'd manage the deallocation properly.
Could it really be the Receptionist's responsibility to notice that its own deallocation is in progress before requesting a weak reference to self? I would assume that there's some window between when an NSObject's deallocation starts and when that object's dealloc method is called, so signalling within the object from the dealloc method sounds flaky.
Thank you for reading!
PS: heavily edited after reading the questions raised by Ken Thomases.
This has nothing to do with the creation of the weak reference. The line you cite should only be run in a context where something has a strong reference to self.
Think about it: the crash that you're seeing may be during that line within your observeValueForKeyPath:ofObject:change:context: implementation, but, since there's clearly a race between deallocation and the call of that method, the deallocation could also occur during dispatch of that method call (or some other point). You're vulnerable to different crashes. So, no changes to the implementation of the method could possibly fix the problem, since the problem could manifest before your method is even called.
It's your responsibility to keep a strong reference to an object if you're going to be calling methods on that object. Or, from the other perspective, to avoid calling methods on object pointers that you're not sure will live for the duration of the call (because you hold a strong reference or some other API guarantee).
With KVO, you need to remove observers before releasing your last strong reference.

What is the correct way to be sure that the object will be there and it won't leak while using blocks with ARC on iOS?

Which of the following code section is correct?
Definition of correct for "me":
It should not have a retain cycle and so should not leak.
It must guarantee the running of method2 and method3. So MyObject variable in block must never ever be nil.(which may occur in __weak definitions...) (I do not want to check if it is nil to prevent crash. I always want it to be non-nil)
Update: (Additional Info)
Instruments tool did show strange leaks until I replace __block with __weak. However, after that I remembered that __weak references may disappear anytime. I have to be sure that it doesn't disappear and leak too. I don't have a timer. This someMethod is called on main thread when it observes a specific NSNotification.
#implementation MyObject...
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
__weak MyObject *weakSelf=self;
abc.onSuccess=^{
__strong MyObject * strongSelf = weakSelf;
[strongSelf method2];
[strongSelf method3];
}
}
OR
#implementation MyObject...
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
__block MyObject *blockSelf=self;
abc.onSuccess=^{
[blockSelf method2];
[blockSelf method3];
blockSelf=nil;
}
}
Update 2: Actual Code which always leaks if I don't use __weak:
__block RButton *_self=self;
_aimageView.onSuccess=^(void){
[_self.headerLabel setText:[_self.book title]];
_self = nil;
};
A block can mention self without causing any leak. So the first thing to do is specify the circumstances. Why do you think your block leaks? Have you checked? There's no point worrying if there is no reason to worry.
If the block's mentioning self does cause a leak, then the steps you can take depend upon the reason why that is happening. But you haven't shown us that. For example, a dispatch timer block that mentions self might cause a retain cycle, but when you are done with the timer you can break the cycle, so then there's no leak.
Thus it is better to understand a particular retain cycle than to program every block defensively when you don't have to.
EDIT (in response to your comment) This code from my book demonstrates various ways of handling memory management in an NSNotification observer situation: click here
I have looked at your actual code in "Update 2", but it's missing a lot of information. For example, is _aimageView an instance variable? local variable? or what? And what causes this onSuccess to be called?
If _aimageView is a local variable then I don't see evidence of a retain cycle.
My first thought is I don't understand why you want to guarantee that the code inside the body of the block runs in this example. It looks like the code inside is just updating some UI elements. Well, if the UI is no longer displaying (as when the current object has no references to it other than perhaps by this block), what's the point of updating the UI elements?
It's important to know what causes onSuccess to be called because different types of callbacks require different memory management architectures. For example, if the block is fired in response to a touch or some kind of event like that, then chances are that the object pointed to by self (which is probably some kind of view or view controller) must be still alive in order that the event occurs. If that's the case, then __weak will do what you want.
Basically, by the naming of these variables, it is reasonable to conclude that _aimageView is probably an image view that is conceptually "owned" by the current object, and the onSuccess is a completion block that is "owned" by the image view. Unless some other object has a strong reference to it, the "owned" object's lifetime is limited to its "owning" object's lifetime. Thus the block will not outlive the image view, which will not outlive the current object.
The only way that what you are afraid of (when the block runs, the object pointed to by self is deallocated) can happen, is if some other object stores a strong reference to _aimageView, or to the block. For the block, it's very unlikely that a "success block" of one object will be stored with other objects. For the image view, it's similarly unlikely if the image view "belongs" to the current object. (It's conceivable that it may be stored by the autorelease pool or something; but the autorelease pool will not call stuff on it except release, so that's not a problem.)
The only exception I can think of is if the image view is kept by a pending network operation or something, which when it is done calls the onSucess block. But if that were the case, I would say it's bad design to have a single object serve as both a view and a network operation. Rather, in that case, one should have a dedicated network operation object, which is a local variable, and set a completion block on it (e.g. store image in image view, set labels, etc.), start the operation, and not need to store the operation. Then the block can refer to self strongly, but there is no retain cycle.
To summarize, the block (and the image view that owns it) should fall into one of two categories, based on who keeps it alive (i.e. who retains it, who maintains a strong reference to it):
If self keeps it alive: e.g. A view controller keeps its views and subviews alive. In this case, it is safe to use __weak because the block does not exist outside of the life of self.
If someone else keeps it alive: e.g. an alert view -- you just create it and show it; the system maintains it on screen afterwards. In this case, self should not (and does not need to) have a reference to it, and it's okay to reference self strongly in the block; it won't cause a retain cycle.
Try to avoid situations where both self and someone else keep it alive.
As you require to guarantee that method2 and method3 are executed then you have a requirement that the object referenced by self stays alive. To do this you follow the standard pattern: keep a strong reference for as long as you need it. Your second code fragment does that.
Reference cycles are not inherently bad, it is unmanaged ones that are. Here you make a cycle and then break it, so there is no issue.
(Note as you can send a message to nil the first code fragment will not crash if strongSelf is nil - it just won't do anything.)
-(void)someMethod{
AnotherObject *abc=[[AnotherObject alloc]init];
abc.onSuccess=^{
[self method2];
[self method3];
}
}
This will make. It won't cause a retain cycle.

Confusion about ARC , AutoRelease

I am new to IOS development and I have started to learn objective c to program towards IOS 7. and as I know, it is way easier to code now than it has been before because of the Automatic reference counting.
there are a couple of things I do not understand . in MAIN method we have the autoreleasepool block, so my first question is that in order to enable ARC , the code has to be inside this block? if no, then what is the difference between the code that is inside autoreleasepool and the rest those aren't?
my second question is that when I am writing my IPHONE programs , I have bunch of classes and non of those codes are inside "autoreleasepool" , only the code inside the MAIN method.
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([HomepwnerAppDelegate class]));
}
}
so , does this mean that this block somehow magically gets applied to all lines of code inside any other classes of the same program?
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
assume we have a method like this :
- (void)doSomething {
NSMutableArray *allItems = [[NSMutableArray alloc] init];
NSString *myString = #"sample string";
[allItems addObject:myString]
}
then when we call this method and it exits, what would happen to those local variables defined inside the method ? is there any difference in the outcome if we are using ARC or not ? (Object are still in the memory or not)
Autorelease pools predate ARC by about 15 years. Cocoa uses a reference-counting memory management scheme, where (conceptually, at least) objects are created with a reference count of 1, retain increases it by 1 and release decreases the count by 1, and the object is destroyed when the count gets to 0.
A problem with this scheme is that it makes returning an object kind of awkward, because you can't release the object before you return it — if you did, it might be destroyed before the other method got to use it — but you don't want to require the other method to release the object either. This is where autorelease pools come in. An autorelease pool lets you hand an object to it, and it promises to release the object for you later. Under manual retain/release (the way we used to do things before ARC), you did this by sending autorelease to an object.
OK, so then ARC comes into the picture. The only thing that really changes with ARC is that you aren't the one writing retain, release and autorelease anymore — the compiler inserts them for you. But you still need an autorelease pool for autoreleased object to go into.
As for your second question:
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
assume we have a method like this :
- (void)doSomething {
NSMutableArray *allItems = [[NSMutableArray alloc] init];
NSString *myString = #"sample string";
[allItems addObject:myString]
}
then when we call this method and it exits, what would happen to those local variables defined inside the method ? is there any difference in the outcome if we are using ARC or not ?
If you're using ARC, the compiler will release any objects referenced by local variables. If you're not using ARC, you'd need write [allItems release] yourself, because the variable going out of scope does not magically cause the object it references to be released.
new to IOS development
Best not to worry, Automatic means that you mostly concentrate on other things ^)
does this mean that this block somehow magically gets applied to all lines of code inside any other classes of the same program
Yes. You're in main function, so all the code that is executed has to be inside this function - your app will terminate once it ends. Unless you create a separate thread, but it's hard to do that by accident.
the code has to be inside this block
As said above, all of your code on main thread will execute within this block.
what would happen to those local variables defined inside the method
You're guaranteed that they will be destroyed before returning.
in MAIN method we have the autoreleasepool block, so my first question is that in order to enable ARC, the code has to be inside this block? if no, then what is the difference between the code that is inside autoreleasepool and the rest those aren't?
ARC is enabled by corresponding Objective-C compiler setting. If you create a new project in the latest version of Xcode it will be enabled by default.
The #autorelease keyword places code inside the curly brackets into autorelease pool scope. Autorelease pools are used both with ARC and manual memory management.
my second question is that when I am writing my IPHONE programs , I have bunch of classes and non of those codes are inside "autoreleasepool" , only the code inside the MAIN method.
iOS applications are event based. Main thread starts event loop when you call UIApplicationMain function processing touch events, notifications etc. This event loop has its own autorelease pool that autoreleases objects at the end of the loop iteration. This autorelease pool has nothing to do with the autorelease pool you see in main function.
My last question is that whether with ARC or without it, if we had a declared pointer variable inside a method, does the object gets released/destroyed when the method returns/exit?
If you use ARC the objects will be released (unless you return a reference to an object from the method). In MMR you would need to manually send release message to destroy the objects.

Proper memory management when invoking a delegate callback that may cause object to be released

I'm trying to figure out the best practice for memory management around invoking a delegate callback.
One issue I had seen in the past is that invoking a delegate callback may cause the object to be deallocated before returning, which may cause it to crash if the object tries to access its own properties after invoking the callback.
For example, an object (e.g. A) may do something like this:
- (void)doStuff
{
[_delegate done];
NSLog(#"msg = %#", _msg);
}
If invoking done leads to A getting deallocated, the subsequent attempt to access _msg will result in a BAD_ACCESS crash.
It is possible to get around this by, say, delaying the invocation of done till the next run loop (e.g. by doing a dispatch_async), but that would force us to have to make it asynchronous. Alternatively, we can retain self prior to calling done and releasing right after, but that just seems like a hacky workaround as well. Does any one have a recommended style for dealing with this issue?
I'm not sure this question really has anything to do with 'delegates' to be honest but more just memory management in general.
If you're not finished with an object make sure you are still 'retaining' it. When you're finished with it 'release' it and don't access it any further.
Also try and move to ARC if possible and life becomes much easier! :)
It's crashing because the delegate you want to call refers to a deallocated object.To fix this crash you need to set Delegate = nil; in your dealloc method.
You can not set property of delegate as retain as it will cause issue in memory management.
It shouldn't be possible, that the delegate method releases the sender. What let you run in this situation?
It is always possible to pair +1 with -1 methods in one (C) block.
If you work with MRC:
Anyway, I would prefer a retain + autorelease on sender in the delegate method before causing the deallocation over a retain + release in the delegate. Therefore the sender should be added as a parameter to the delegate method as usual:
- (void)senderIsDone:(Sender*)sender
{
[[sender retain] autorelease];
…
[sender release]; // Something like this in your code
}
But at all: This should not happen.
Another strategy is to delay that code that causes the deallocation. In the example above
- (void)senderIsDone:(Sender*)sender
{
[sender performSelectorOnMainThread:#selector( release ) withObject:nil waitUntilDone:NO]; // Whatever make the sender disappear
}

Resources