When should I release [[UIApplication sharedApplication] delegate] object? - iphone

I'm using the following code many times in my app (especially to manage a NavigationController):
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
When should I release it ?
Thx for helping,
Stephane

Don't. Never release your application delegate - it is managed automatically by the OS.
If you look in your app's main.m file, you'll see some code that initializes an instance of UIApplication that represents your app - it is its responsibility to manage the application delegate's lifecycle, not your responsibility.
EDIT as #Goz points out, you should release it if at some point you retain it. However, since the application object (and therefore, by extension its delegate) is guaranteed to remain in scope for the life of the app (unless you go messing with it), it's far better to simply not do any memory management on the delegate, as this avoids the possibility of accidental over-release or other related issues.

Short answer: never ever release your application delegate.
Explanation:
It often helps me how to address mem-mgmt issues, when I check how the things are declared. Take a look how delegate property is declared for UIApplication:
#property(nonatomic,assign) id<UIApplicationDelegate> delegate;
As you can see, it is assigned property meaning all mem-mgmt done here is just assigning pointers for an instance variable. It means calling release on your application delegate will result in -dealloc method being executed for your MyAppDelegate. Go and try this in debugger and you'll see that your application will receive EXC_BAD_ACCESS - i.e. it will crash.
EDIT: However, as Goz suggests, you can call retain and then release. But in the first place, it doesn't make sense to do this retain/release thing on app delegate.

Related

Objective-c Delegate used in some viewController must be released?

In my app delegate I have one object that I need to use in some different 3 viewControllers.
To use it I do in the interface
NewsPadAppDelegateiPad *delegate;
and in the implementation I do
delegate = (NewsPadAppDelegateiPad *)[[UIApplication sharedApplication] delegate];
[delegate.reader setDelegate:self];
....
[delegate.reader doSomthing];
When In my dealloc method I do
[delegate release];
delegate=nil;
I receive the error
[CFString release]: message sent to deallocated instance 0x9d4fac0
I really need to release that?
In general, you should not retain your delegates: this lets you avoid retain cycles - situations when two or more objects retain each other in a cycle, preventing the whole group from being deallocated.
This looks to be a pre-ARC code, so you should simply avoid retaining and releasing your delegate.
In ARC code you should declare your delegates __weak unless you have specific reasons to use strong references (specifically, you retain your delegate when you want to own the delegating object; this is very rare - in fact, it's usually the other way around).
Here is a good discussion of the topic on why delegates are not usually retained.
According to Cocoa's memory management name convention, you don't own the object so you don't release it. It will be released for you when it goes out of scope.

Should I implement dealloc in my app delegate?

Should I implement dealloc in my app delegate and release my ivars there? As I understand it, when an app gets terminated, all the memory associated with it gets freed automatically. So basically, there's no need to release any ivars yourself at termination.
I've found this question here already: Does it make any sense to release ivars in appdelegate's dealloc?
One of the answers says that objects might have clean up code in dealloc, so you might want to release ivars yourself at termination. But when I put an NSLog in the dealloc of my app delegate, it's never called. My assumption is there's no use at all for it so I don't even have to implement it, am I right?
It may be necessary in future iOS releases. For the sake of forward compatibility, and since Apple seems to recommend it I would release those ivars.
You are right, you don't need to release your ivars in dealloc (The example templates that come with the SDK do have a -dealloc though). The OS will reclaim any memory associated with you app. If anything, it will just add a small amount of overhead. Also, as far as I know, there isn't any guarantee by the environment that the -dealloc in your app delegate will ever get called, so it may never even execute.

Releasing a delegating object in its delegate callback method

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.

Releasing reference to UIApplication's delegate results in EXC BAD ACCESS, why?

I am running my application through xcode's static analyzer and it pointed out that I had a potential leak in a file:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
So after the code I do [delegate release]. This results in an EXC BAD ACCESS when the view controller I am doing this in pushes a new view controller onto the navigation stack. If I comment this out, it's fine.
I have run through the debugger and it doesn't actually crash when the delegate reference is released, but just when the next controller is pushed.
It isnt the code which runs between the declaration and the release as I tried commenting it out to see what happens.
Calling the delegate Method does not retain the object. So you shouldn't be in charge of releasing it. Are you sure that the static analyzer is referencing this particular line of code? UIApplication itself does not retain but assign the delegate.
In your code you just get a reference to the application delegate object and do not retain it anywhere - so you should not release it.
So either static analyzer gives false positive here or there's some other error in the code around. But, again, considering just this line you should not release delegate.

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