Releasing a delegating object in its delegate callback method - iphone

I'm trying to figure out what the recommended practice is for the following situation. Certain objects, such as CLLocationManager or MKReverseGeocoder, send their results asynchronously to a delegate callback method. Is it OK to release that CLLocationManager or MKReverseGeocoder instance (or whatever class it may be) in the callback method? The point is that you no longer need that object around, so you tell it to stop sending updates, set its delegate to nil, and release the object.
Pseudo code:
#interface SomeClass <CLLocationManagerDelegate>
...
#end
#implementation SomeClass
...
- (void)someMethod
{
CLLocationManager* locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// Do something with the location
// ...
[manager stopUpdatingLocation];
manager.delegate = nil;
[manager release];
}
#end
I am wondering if this usage pattern is considered to be always OK, if it's considered to be never OK, or if it depends on the class?
There is an obvious case where releasing the delegating object would go wrong and that is if it needs to do stuff after it has notified the delegate. If the delegate releases the object, its memory may get overwritten and the application crashes. (That appears to be what happens in my app with CLLocationManager in a particular circumstance, both only on the simulator. I'm trying to figure out if it is a simulator bug or if what I am doing is fundamentally flawed.)
I have been searching and I cannot find a conclusive answer to this. Does anyone have an authoritative source that can answer this question?

No. That pattern is always considered to be wrong. It breaks the Cocoa Memory Management Rules. The manager object was passed in as a parameter. You did not obtain it by new, alloc or copy, nor did you retain it. You therefore must not release it.

This is a very good question, I waited few hours in hope someone would give a sufficient answer, but because no one even replied, I'll give it a try. First I'll comment on your approach, then I try to suggest how I would go around this.
It's definitely a very bad idea to release - thus deallocate an object from its delegate. Just think about how objects (like a CLLocationManager) do call their delegates - they just call them in the middle of some method. When call to delegate is finished, code's execution comes back to a method of an object that has already been deallocated. BAM!
Let's forget for a moment about the fact that this is a bad idea. I see two options how to fix that easily. First, autorelease instead of release gives an object a little longer time spam - it'd at least survive returning from delegate. That should be sufficient for most of the cases, at least if author of API did her job well and encapsulated logic behind the main API class (in case of CLLocationManager it might be waiting for GPS to turn off...). Second option would be to delay releasing (performSelector:withObject:afterDelay: comes to mind), but that's more of a workaround for badly implemented APIs.
So if releasing it is not a good idea, then what is ?
Well, what do you really gain by releasing a CLLocationManager ? Freeing those few bytes of memory is not going to save your app from terminating when system is out of memory. Anyway, is it really only once that you need the current user's location ?
I suggest that you encapsulate tasks related to CLLocationManager into a separate class, probably even a singleton - that class would become its delegate, and it would take care of communicating with CLLocationManager and informing your application about results (probably by sending NSNotification). CLLocationManager would be released from that class's dealloc, and never as a result of a delegate callback. stopUpdatingLocation should suffice, freeing few bytes of memory - well, you can do it when your app is entering background, but as long as your app runs, freeing those few bytes do not make any significant improvement in memory consumption.
** Addition **
It's natural, and correct, for a delegate to have ownership of an object for which it acts as delegate. But the delegate should not release the object as a result of a callback. There's one exception to this though, and it is the callback telling you processing is over. As an example for this is NSURLConnection's connectionDidFinishLoading: which states in documentation "The delegate will receive no further messages". You can have a class downloading bunch of files, each with a different NSURLConnection (having your class as delegate), allocating AND releasing them as download of files progress.
CLLocationManager's behavior is different. You should have only one instance of CLLocationManager in your program. That instance is managed by some code, probably a singleton - one that could be released when application goes into background, reinitialized when it wakes up. CLLocationManager's lifespan would be the same as of its managing class, which acts as delegate as well.

Just like Michal said there is absolutely no good reason to release the manager object for memeory savings.
Also, just likeJeremyP said, it would be completely incorrect pattern wise and design wise to release an object inside another function that only receives that object. It goes against all the rules.
However, what would be correct is to simply stop the updates and set the managers delegate to nil as you are already doing. So the only thing you need to remove is the [manager release] line.
My guess is that you are creating a manager in a local scope and therefore are trying to work out how to make sure the the manager gets released. The correct thing to do here would be to create a manager as an instance variable of your class and then just release it in the class dealloc.

Another reason why your pattern is a bad idea, is that for something like a CLLocationManager you generally want to tell it to stop receiving updates if the screen goes to sleep - you can only do that if you maintain a reference somewhere that you can tell to start/stop. And if you are maintaining a reference, then you might as well fully manage it.

Related

How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C

I'm coding a library (Obj-C for iPhone) that I want to package and sell, so I obviously need to work out any design kinks before listing it for sale. I am also utilizing this library to help me develop another app.
My library is heavily built on task delegation. The primary function I have is to launch a (potentially) long-running process, and when it's done, I call a Delegate Protocol method in the class's delegate.
An additional complicating factor here is that I will often schedule this task to fire off every 30 seconds or so. Usually, I do this with [self performSelector:#selector(someMethod:) withObject:nil afterDelay:30] rather than using an NSTimer. Then, when the delegate method successfully returns, I process the returned data and trigger the method to fire in another 30 seconds. This gives me 30 seconds BETWEEN method calls, rather than 30 seconds FROM THE START OF ONE CALL TO THE NEXT. (This is mainly just in case the call ever takes more than 30 seconds, which shouldn't happen.)
The error that I'm catching is that sometimes, the Delegate callback method is failing with an EXC_BAD_ACCESS error. Based upon my investigation, it appears that the delegate of my class library has disappeared (been released/dealloced) since the long-running process was initiated. Thus, when it calls [[self Delegate] doSomeDelegateMethod], it's accessing a released object.
I tried first checking [[self Delegate] respondsToSelector:#selector(doSomeDelegateMethod)], but even that access apparently also throws the EXC_BAD_ACCESS.
It doesn't yet seem that checking for [self Delegate] == nil is the right way to go, either.
One way I think I have solved the problem, in this specific instance, is when the view controller that instantiates my object is disappearing (and therefore on its way to the garbage dump), I call [NSObject cancelPreviousPerformRequestsWithTarget:self]. This apparently fixes the problem. (Does this "fix" also indicate that my object "knows" about the call to come and keeps itself in memory until it can successfully, desperately, fire off its final shot?)
This appears to put a band-aid on a bullet wound. Yes, it appears to stop my app from breaking this time, but my gut tells me that this is a poor solution.
I've also considered setting the custom object to nil in my viewWillDisappear:animated: method, which is probably the correct coding pattern, but it doesn't seem right that the customer has to be so precise in handling my objects.
What's really bugging me, though, is that I haven't yet found a way, as a library developer, to "box in" my code so that it won't throw an exception for the user if they don't do just the right things. Basically, I'd like a way to have my object:
Get a request.
Go look for the answer.
Find the answer.
Try to return the answer.
Realize that there's nothing on the other end.
Give up and die on its own. (OK, so "die on its own" probably won't happen, but you get the point.)
One interesting side point:
A main reason I have for preventing this type of error from occurring is this:
I did the following steps:
Built my library's .h/.m files.
Generated my library's .a output file.
Imported my library's .a/.h files into another project.
Had the error described above.
Got to peruse the code from one of the .m files that SHOULD have been hidden inside the .a file.
Am I missing something here? Am I really risking exposing my entire source code if it ever throws an error for a client? (This is just a side issue, but I'm fairly concerned here!)
Thanks for any help you can provide to help me be a better programmer!
---EDIT---
I have found another reason why this is important. In another view controller, where I am using this library, I implemented the NSTimer strategy. If the view is popped from the navigation stack (i.e., in the viewWillDisappear:animated: method), I invalidate said timer. So, no more calls will go to my library after the view disappears.
Here's the rub: what if the view disappears IN THE MIDDLE of the long-running call? Yes, it's tricky and unlikely to do, but I just had it happen on the simulator. In particular, THIS is why I'm looking for a workaround to let my code realize "hey, there's nothing on the other end of this pipe" and then fail gracefully. Anyone?
Thanks!
There are several approaches to this problem:
The traditional delegate approach (UITableViewDelegate) makes it a requirement to clear yourself as delegate before going away. This is traditionally done in dealloc of the delegate with otherObject.delegate = nil. Failure to do so is a programming error. That's basically what you're seeing. This is the common pattern when the delegate and the delegator have basically the same lifespan.
Another approach is how NSURLConnection handles it: retain your delegate until you're done. The key to this working well is that NSURLConnection has a lifespan of its own, so the retain loop will work itself out automatically. UITableView could not retain its delegate because this would almost always create a permanent retain loop. If your object lives for a while and then goes away, then this makes sense. Typically here the delegate has a much shorter lifespan than the delegator, so the retain loop doesn't hurt anything.
Any object that calls performSelector:withObject:afterDelay: should always call cancelPreviousPerformRequestsWithTarget:self in its own dealloc. This has nothing to do with your delegate, though. It should be self-contained to the object itself. (I don't know why I keep thinking this is true, and then proving to myself again that it isn't. When you call performSelector:...afterDelay:, you are retained, so you can't deallocate before it fires. My SIDE NOTE, while true, isn't relevant here.)
SIDE NOTE cancelPrevious... is really expensive in my experience. If you have to call cancelPrvious... very often, I recommend keeping your own one-shot NSTimer and just resetting it when it fires to get the same effect. performSelector:withObject:afterDelay: is just a wrapper around a one-shot timer.
I'm answering myself because the page warned me to not have extended discussions in the comments... :)
OK, so it appears that part of my answer is that [self performSelector:withObject:afterDelay:] automatically retains my object until it gets to "fire that shot", at which point I'm guessing the view controller dies.
So, now it makes sense why my custom class is trying to access a released object when it tries to return its answer to its delegate, which is an __unsafe_unretained object, meaning that it can die at will (I think).
What I'd like now is a way to prevent this from causing an error. In .NET, I've got all sorts of error handling options to do this, but I'm unable to think of a fail-safe "bail out" here.
I've tried [[self Delegate] isKindOfClass:..., but can't be sure what kind of class the delegate will be, so it won't work.
I've also tried [[self Delegate] respondsToSelector:#selector(...)]. I'm not sure why this fails, but I get the EXC_BAD_ACCESS here, too.
What I don't want is my customers to be able to crash my product with such a simple, innocent mistake.
As an aside, does anyone know why this sort of failure gives me such easy access to the contents of the .m file that should be hidden inside my .a file? Did I build my library incorrectly?
Thanks!
Try setting Delegates to nil in dealloc.
example:
self.fetchedResultsController.delegate = nil;
I've seen this problem a lot lately and usually fix the problem. Even though delegates are supposed to be weak references, sometimes some private implementation is using them as well.
If I release, I get bad access, if I retain, I leak
That's where I had a similar problem.
Edit: When using ARC, you can still override dealloc for cleanup, you just can't call [super dealloc] or release anything.

Bad-practice to retain 'self'?

I have a simple query that I'd like cleared up by someone... Is it bad-practice to retain self?
I have a server request object that I'd like to make. I'd like to be able to use it in the following fashion:
ARequest *request = [ARequest request: someParam];
request.delegate = self;
[request begin];
In order for the object not to self destruct as soon as the autorelease pool is drained, I imagine I need to call a retain in it's init method and then a release once the server response has been received, processed and delivered to it's delegate.
However, something is raising a warning bell in my head with this approach. Better ways to do it?
There is nothing wrong with retaining self, as long as you release it at some well-defined point in accordance with normal memory management protocol. If an object requires itself to exist until some condition is met, it should take responsibility for that, in the same way as it does for any other object it requires to continue existing.
Introducing otherwise extraneous manager objects or foisting the responsibility off on the object’s owner for superstitious reasons would be the real anti-pattern here.
(The equivalent approach in garbage-collected code would be for the object to exclude itself from garbage collection while results are pending, or root it through a collection of some sort if you dislike that idea.)
It's not unheard-of, but it is somewhat uncommon. The main way I've seen it used (and used it myself) is when you're dealing with some sort of semi-synchronous object (by semi-synchronous I mean that it does not block the main thread, but it also does not execute on a background thread; an NSURLConnection would fit this bill). For example, I wrote a subclass of NSWindowController that was specifically for displaying a window as a sheet and for invoking some certain delegate callbacks. Basically, you'd alloc/init a new sheet controller and invoke beginSheetForWindow:. This would run the sheet semi-synchronously, and then invoke an appropriate callback when the sheet was dismissed.
Since the invoking object doesn't necessarily "own" the sheet (think of it as a Mac version of a modal view controller on iOS), the sheet controller does [self retain] immediately before showing the sheet, and [self release] immediately after cleaning up and invoking callbacks. The purpose behind this was to ensure that the controller object would stick around until the sheet was done. (The sheet, IIRC, was retained by the runloop, but I also needed the controller to stick around)
Like I said, it's very rare to come across a situation where you would want to [self retain], but it's not impossible. However, as a general rule of thumb, if you think that you need to [self retain], you may want to think again.
Easiest way to do this would be to create an iVar for your request, retain the request when you start it and release it when the last delegate method is called.
Is ARequest a class you created? Does it create a new thread to asynchronously submit the request?
I once did the same thing as you. I wrote a Category-Method on NSString to send it it to a server, that will print it. In the Category-Method I had to call [self retain], so that the callback methods could be a NSString-Categroy-Method to.
I felt so bad about it, that I rewrote everything to use a Singleton, that is accessed by the Category-Method. So the Singleton will retain the string as long as necessary.

iPhone: Does it ever make sense for an object to retain its delegate?

According to the rules of memory management in a non garbage collected world, one is not supposed to retain a the calling object in a delegate. Scenario goes like this:
I have a class that inherits from UITableViewController and contains a search bar. I run expensive search operations in a secondary thread. This is all done with an NSOperationQueue and subclasses NSOperation instances. I pass the controller as a delegate that adheres to a callback protocol into the NSOperation.
There are edge cases when the application crashes because once an item is selected from the UITableViewController, I dismiss it and thus its retain count goes to 0 and dealloc gets invoked on it. The delegate didn't get to send its message in time as the results are being passed at about the same time the dealloc happens.
Should I design this differently? Should I call retain on my controller from the delegate to ensure it exists until the NSOperation itself is dealloc'd? Will this cause a memory leak? Right now if I put a retain on the controller, the crashes goes away. I don't want to leak memory though and need to understand if there are cases where retaining the delegate makes sense.
Just to recap.
UITableViewController creates an NSOperationQueue and NSOperation that gets embedded into the queue. The UITableViewController passes itself as a delegate to NSOperation. NSOperation calls a method on UITableViewController when it's ready. If I retain the UITableViewController, I guarantee it's there, but I'm not sure if I'm leaking memory. If I only use an assign property, edge cases occur where the UITableViewController gets dealloc'd and objc_msgSend() gets called on an object that doesn't exist in memory and a crash is imminent.
In the general case, a delegate owns the objects it has set itself as the delegate to, or at least retains references to them directly or indirectly. In the dealloc method, a delegate should either release all objects that it is the delegate of in such a way that prevents future callbacks, like NSTimer invalidate, or clear the delegate member of those objects that may persist.
While it is only convention that prevents retaining a delegate, it is convention based on good design. In your case, wouldn't the results be discarded anyway since the delegate is being disposed?
You can make the delegate property of your NSOperation atomic by not setting the nonatomic flag and synthesizing the getter and setter. Or you can use performSelectorOnMainThread before using the delegate member.
To recap, there is usually a better solution than retaining the delegate.
I really wonder though if the "don't retain your delegate" rules still apply specifically to multi-threaded object/delegate relationships, especially the one you're writing about. I found my way to this question because I'm in exactly the same situation: I'm running a finite but unpredictable length asynchronous network operation (it will finish and self-terminate "sometime soon") in an NSOperation, and using a delegate stored in the NSOperation to notify completion of the operation back to the original requestor object.
Retaining the delegate in this case makes perfect sense to me. The operation will complete eventually, it will call the "done" method on the delegate, and then will release the delegate and self-terminate. If the calling object would have been dealloc'd while the NSOperation was running, it just sticks around a little longer until the operation completes.
Note that marking the delegate property atomic as drawnonward suggests is in itself not sufficient to protect against race conditions! Setting a property as atomic only means that a reader or writer of the property will write or read an entire whole value at a time, nothing else. The following sequence would result in a crash:
(NSOperation thread): NSOperation has finished and is preparing to notify the delegate object . The code atomically reads the value of the delegate property preparing to call its "done" method.
----> Thread switch to main
(main thread) the requesting object is dealloc'd, and in -(void)dealloc (atomically!) sets the NSOperation's delegate property to nil, dealloc finishes, and the object is now gone
-----> Thread switch to NSOperation thread
(NSOperation thread) calls [delegate allDone] and the program crashes (if you're lucky) because the delegate object is gone. If you're lucky. Maybe something else was allocated in that space in the meantime and now you have unpredictable corruption, what fun!
The key thing here is that the retain cycle is temporary by its very nature -- the NSOperation will complete and clean up all on it own. It's not like a UITextField and a UIViewController holding retained references to each other that will never go away and thus leak the memory.
It seems to me that retaining the delegate in the case of an asynchronous, limited, self-terminating operation is the cleanest and most robust implementation.
EDIT:
if you absolutely must not retain the delegate because it causes memory problems, then instead the delegate object and the operation object must both use an explicit locking mechanism to synchronize access to the delegate pointer stored in the operation. "atomic" properties do not provide a thread-safe protocol to marking the delegate pointer nil.
But I think this gets really complicated and full of race conditions. I think at the very least that you must in the delegate object's dealloc, run a locking protocol to make sure that the operation's delegate pointer is safely set to nil so that arbitrary thread interleaving cannot under any circumstances call to a dealloc'd delegate object.
Slavish adherence to rules sometimes makes things way more complicated than they need to be. It's best to understand what the rules are, why they are there, and so you know when it makes sense (like I believe it does in this very particular scenario) not to follow them, and what the advantages/disadvantages are of doing so.
I approach this a little differently, and I do not retain delegates.
If I need to lose the view, I cancel the NSOperation. I believe that its good design that if a thread's return value has nowhere to go, then the thread should stop.
I also have seen the edge case where the thread cannot be stopped. In this case, I nil the unretained delegate, just to be sure, and check that the delegate is not nil before making the callback.
Holding on to an object, even temporarily, when its no longer needed, especially on the iPhone chews up memory and, in my opinion, is bad design.
As per #Bogatyr's answer, a simple check for nil before calling [delegate allDone] is much cleaner.
You could retain the UITableViewController at the beginning of the NSOperation and release it at its end.
Alternatively, you could set it to nil after it is released so the dangling call from the NSOperation won't crash your program.
Depending on how the NSOperation is executed you could also autorelease the UITableViewController instead of releasing it, so the NSOperation can still use it.
However, all these things really only cure the symptoms, not the illness. The correct way to do it is outlined by drawnonward.

What sort of cleanup work should I do aside from dealloc in an iPhone app?

Right now, I do most of my cleanup work in dealloc (cleaning up IBOutlets, allocated objects, etc.). What other places should I do cleanup work in order for my app to be a well-behaved one? Could you explain the things that are typically done in those methods as well?
For example, viewDidUnload, applicationWillResignActive, etc.
For views, I typically release any UI widgets that were created from the NIB file in viewDidUnload. Any models or other objects I clean up in the viewController's dealloc.
Sometimes I have views that create a model (say a Dictionary of section names to section rows) from a primary data object. If I create/build an object in viewDidLoad I will release it in viewDidUnload (since my viewDidLoad will get called again when the time is right).
I believe that in SDK 3+ you don't have to typically worry about implementing didReceiveMemoryWarning directly as the new viewDidUnload method is the main place to do your view cleanup.
For normal objects (objects without special life cycles like a view controller has) I just release their member vars in the dealloc.
Don't forget:
- (void)didReceiveMemoryWarning
Note: This "Answer" is only relevant to app quit/termination.
According to the answer I received to my question, it's not even necessary at all to do cleanup work like cleaning up IBOutlets, allocated objects, etc. Just save state (as necessary) when your app quits, and let the iPhone OS handle the final cleanup.
Note that your question is ill-formed. The -dealloc method of UIApplication is never called. The -dealloc of your application's delegate is never called. That means that any objects that are retained by your application's delegate will never be released, so their dealloc is never called.
You should be doing your cleanup in your application delegate's applicationWillTerminate:
Since your application is about to die, you don't really need to do anything except give back non-memory resources, make sure your data files are properly closed, and that your NSUserDefaults are synchronized so you can restart properly the next time you are run.
However, any object that might be allocated and deallocated repeatedly over the life of the program deserves a proper Obj-C dealloc method, as documented by Apple, and it is good practice to write this for all your classes, even though they won't be called, just so you build good habits, and readers won't be confused. Also, it saves maintenance headaches in the future, when you DO create and destroy multiple of these, for example in your unit tests.
I would use the [yourObject release] method, but replace yourObject with an object

Is it acceptable to release object in a method of the object's class

Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
First, I would want to have a really good reason to release myself. The only time I've done it is in a singleton that I dump to free up large chunks of memory on an iPhone. This is a rare event.
Your code is part of the class object. Hence, it is not really a problem to call [self release]. Of course, you are much safer, from an encapsulation perspective, if you call [self autorelease]. At least then, if someone up the call chain calls your methods, you don't cause an exception.
Andrew
You should only do this if you've done something like
[self retain];
But it's unclear why you would do that. The Cocoa Memory Management Documentation might help
While I doubt that immediately after your release, memory would move much, keep in mind that the code that your [self release] is in, resides in a memory block inside your object, self. Thus, it is possible that after returning from [self release], you end up in code that is no longer allocated and is being written over by some other process. Can't say for sure how probable that is, but it seems possible.
I have used this technique once before, for a similar situation (standalone object handling response from a web delegate that may outlive the view that launched the request).
It does work, but is actually rather tricky to get right. Since then I have found that using NSOperations in an NSOperationQueue is a much more solid and well-understood approach to encapsulating background actions that run independent of the requestors. Usually when an operation is done a notification is sent out on the main thread informing whatever caller might still be around that data is ready for pickup.
Plus for simple remote requests you can use the simpler synchronous URL calls in your Operation since they run in a separate thread and will not block the main thread while data is incoming (handy when fetching small images from URL's, for example).
You can do it. It works. It is a bit dangerous, especially since optimizing compilers can rearrange your code in ways you didn't intend them to.
A little bit safer is to call [self autorelease], which will release the current object at some point in the near future (the next time through the runloop typically) rather than right away.