release or autorelease? - iphone

should i use release or autorelease for varSecondViewController?
-(IBAction)takeNextStep: (id) sender
{
SecondViewController *varSecondViewController = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:varSecondViewController animated:YES];
[varSecondViewController release];
}

My rule of thumb:
If you're going to use it, and then no longer need a reference to it, release it,
If you're going to pass it back to the caller (i.e. return it), autorelease it.

autorelease is just a release that's delayed until some time in the future, which is guaranteed to be at least the current call stack unless a caller has created its own autorelease pool. You generally use it when you need to release an object in order to follow the memory management guidelines, but that object might still be needed further up the call stack. In this case, you're not returning the view controller and have no intention of directly holding onto it any further, so there's no need for a delay. You can just release.

In this case, release makes the most sense.

Related

Silly memory management issue that has me stumped

I have a property defined as:
#property(nonatomic, retain) UITableView *settingsTableView;
Then in my viewDidLoad method I have:
self.settingsTableView = [[[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped] autorelease];
[self.view addSubview:self.settingsTableView];
[self.settingsTableView release];
Then in the dealloc method of the view controller I have:
[settingsTableView release];
When I attempt to do the release from within the dealloc I am getting a "message sent to deallocated instance". I am starting to second guess myself, anybody see anything stupid in what I've done?
Really appreciate the help on this one!
you're calling release on an object you've already autoreleased. Just get rid of the line
[self.settingsTableView release];
and you should be good.
Note that you should keep the release in the dealloc method, since the property calls retain for you, but not release.
Two things. First, you're over-releasing the table view in the first place: the autorelease call negates the need for a manual release afterwards.
Also, in general, what you release in -dealloc are things that you created in -init, -initWithCoder:, or whatever, not loadView or -viewDidLoad. In this case, the method you're looking for is -viewDidUnload; you just have to set self.settingsTableView to nil in that method, and the property setter will handle releasing it if necessary.
Here is the change you need to make.
self.settingsTableView = [[[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped] autorelease];
[self.view addSubview:self.settingsTableView];
[self.settingsTableView release];
//^^^ This line is bad no need to release this value until dealloc
//if it is defined as retain or copy
Seems obvious. You have already released with
[self.settingsTableView release];
So why release it again in the dealloc?
I believe the problem is related to your use of autorelease when you are allocating and initializing the UITableView.
You also might have a problem with releasing the settingsTableView right after you use it, vs. in the dealloc method. Anytime you alloc/init an object, you should only release it once.
If you use autorelease, the rules are a little different, so I'd recommend reading up on that again. Also, when you pass objects that you've created off to other things, they may take complete or shared ownership of the object by retaining it, meaning that you may or may not need to release it yourself anymore. The documentation for that should be on the method you're calling (like addSubView).

What's the difference between a ModalViewController and NonModalViewController in Iphone?

The difference of look between the two controllers.
And
Game *game = [[Game alloc] initWithNibName:#"mygame" bundle:nil];
I try to put a autorelease at the end of line. the program crashed.
Therefore I am wondering if
[self presentModalViewController:game animated:YES];
would increment reference count by 1?
[self dismissModalViewControllerAnimated:YES];
would decrement the reference count by 1?
After presenting the controller just release it normally, make sure you don't send messages to game after releasing it though. presentModalViewController:animated: increases it's retain count so you are able to release it with out deallocating the object and you can successfully pass ownership to the current view controller.
Game *game = [[Game alloc] initWithNibName:#"mygame" bundle:nil];
[self presentModalViewController:game animated:YES];
[game release];
Then when it comes to dismissing it you shouldn't retain or release, just call the dismiss method.
Don't necessarily think about the retain count (and whatever you don't call the retainCount method on anything and decide what to write based on when is returned, that method is for legacy purposes only). Just match every init/new/copy with a release/autorelease.
(See listing 6-1 on this Apple doc, for prove that you should release it)
Effectively the [game release]; counteracts the init... and the dismissModalViewController... counteracts the presentModalViewController...
No, presenting a view controller only does that, it presents it. You should be calling retain and release at the appropriate times. It's important to keep track of your retain counts.
Keep in mind that when you allocate and initialize, the retain count increases by one. You will have to release that object later.
If you're still unsure, you need to read the Apple docs on view controllers and memory management.

iPhone, method returns an objective-c object with a +1 retain count

I kind of understand why I'm getting this analyzer warning. Because I'm using an object that is being passed in. I've tried autorelease and retain however these cause me other problems like unrecognized selector sent to instance.
The aim of my CommonUI function is to re-use code, but I have to cater for addSubView and presentModalViewController.
Perhaps I'm doing some obvious wrong ?
Change your code like this:
HelpViewController *helpvc = [[HelpViewController alloc] init....];
[vw addSubview:helpvc.view];
[helpcv release];
I think you don't need to pass the other VC.
There are two problems here.
First, if you call [vc release] (as the other answers suggest), you'll certainly make the analyzer happy but likely crash the app. A view controller's view doesn't retain the controller, so any button targets in the view will be pointing to garbage.
You will need to somehow keep the HelpViewController retained for as long as it is showing up onscreen. The "parent" view controller should likely retain it somehow. You could autorelease it, and return it. Then whomever calls showHelpClick... would retain the returned controller.
Second, you don't need to have the (UIViewController *)vc passed in as an argument.

UINavigationController and UIViewController dealloc

I recently changed my app to use a UINavigationController, I was using a UINavigationBar before, with cascade subView adding, which was a bit tenuous.
I'm facing a problem of memory usage. Leaks tool doesn't show any leak, but ViewControllers I create and add to the UINavigationController never seem to be released. So memory usage grows everytime I create a new VC and then press the NavigationController's back button.
I simply create and add my VCs this way:
DetailViewController* detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// setups
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
The app never goes through ViewController's dealloc and viewDidUnload methods. Shouldn't these be called everytime I press the back button?
I've searched many tutorials and read Apple's memory management, but there's nothing about VC's lifetime in memory when using NavigationController.
Maybe you are not doing something wrong and instead you are facing something like this
In the Blog post it was the question whether we have to manually release IBOutlets or not. As it turns out we should. This was reproduceable in iOS 3.1.3 but I didn't test it in iOS 4.0 yet.
The second aproach is to override your view controllers retain and release method and print out the retain count. I had a simimlar problem, that some view controllers dealloc method did not called so I override this methods to see wether someone has still a retain on it. As it turns out it did.
Edit:
When I printed my retain count, it would sometimes reach ~98 caused from the framework, so thats not really to worry.
If your last retain count stays at 2 and the dealloc method won't be called, than there is someone that has still a retain on it.
In this case you should search on other places.
For example another problem I encountered during this same problem:
Sometimes I would use
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateUI) userInfo:nil repeats:YES]
to constantly update the UI. But what I forgot was, that the NSTimer will retain the target object (which was the ViewController). Because the NSTimer retained your view controller your dealloc will never be called because someone (NSTimer) has still a retain on it. So you have to make sure to invalidate the NSTimer BEFORE dealloc method to properly release the view controller.
Edit2 in response for a comment below:
A retain declaired property does as follows (exsample):
- (void)setTarget:(id)value {
if (value != target) {
[target release];
target = [value retain];
}
So it does first release your current self.target then retains the new value. Since you are assigning nil your target will be nil afterwards. Further info about Properties can be found in the Apple doc.
I have seen this as well. As you pointed out, I haven't seen anything definitive in the docs, but my belief is that they are retained in memory until memory is needed. It makes sense from a performance perspective as doing so allows the app to quickly navigate between the different views.
Bottom line is, I wouldn't worry about it. You could fire off some Low Memory Warnings in the Simulator and see if it actually releases your VCs.

Is calling [self release] allowed to control object lifetime?

I want to create an object in Objective C but I don't hold a reference to it.
Is it allowed to let the object control its own lifetime by calling [self release]?
In case you're wondering why I need this: I want to create an object that subscribes to some notifications, but after a while the object is no longer needed and should go away.
So, is the following allowed?
- (void) destroyMyself {
 [[NSNotificationCenter defaultCenter] removeObserver:self];
[self release];
}
If you see this in code, its probably wrong. However there are legitimate response for it in certain circumstances that are arguably defensible. (So make sure you are doing it for the right reasons.)
A good example of when this makes sense, is when you create an object that goes off to download a url. The object sits in memory while downloading the url, then sends a message to its delegate saying the data is ready (or url couldn't be downloaded). Once its message has been sent it destroys itself as its no longer needed. In this situation the code/function that created the 'url downloader' may no longer even be in memory, i.e. if it was called in response to a user selection a menu item or an action in a view controller that is no longer on the screen.
This is useful when the code that creates the "download" object doesn't care if the download completes or not.
The rules are simple. You should only release an object if you own it. i.e. the object was obtained with a method starting "new" or "alloc" or a method containing copy.
Cocoa Memory Management Rules
An object must not therefore do [self release] or [self autorelease] unless it has previously done [self retain].
To quote the great philosopher Alicia Silverstone, "I had an overwhelming sense of ickiness" when I read that. But I couldn't really tell you why.
I think I would use autorelease rather than a simple release since you're still executing code in self when you call it, but other than that I can't think of any technical reasons why it wouldn't work.
It's legal, but be careful. You want to be sure nothing else is going to send you a message after you release yourself.
I've done this kind of thing for a faulting scheme back before we had CoreData.
Well part of the protocol is that if you send release to self, then you should have sent retain once as well, which I suppose you do. Then there is nothing fishy. I mean the allocing code must be able to control the lifetime of your instance; it itself can only prolong its life, never make it shorter (since making it shorter, then you'd suddenly leave the allocing owner of the instance with an invalid pointer).
And I will use [self autorelease] instead of [self release]. Because usually it's called in
- (void)aMethod
{
[self.delegate aDelegateMethod:self];
[self release];
//If you add code related to self here, after [self release], you are making a huge mistake.
}
If I use [self autorelease], I can still do something after autorelease.