I am struggling to find out if pushViewController retains the controller, currently I have the following code (which works) ...
ColorController *colorController = [[ColorController alloc] initWithNibName:nibColor bundle:nil];
[[self navigationController] pushViewController:colorController animated:YES];
[colorController release];
but am considering removing the release and adding an autorelease ...
ColorController *colorController = [[[ColorController alloc] initWithNibName:nibColor bundle:nil] autorelease];
[[self navigationController] pushViewController:colorController animated:YES];
Much appreciated
Gary
This does nothing...
ColorController *colorController = [[ColorController alloc] initWithNibName:nibColor bundle:nil];
[[[self navigationController] pushViewController:colorController animated:YES] autorelease];
You are autoreleasing the return value of pushViewController:animated:, which is void.
Your first snippet is valid, and correct. pushViewController: does indeed retain the controller that is pushed.
Edit: In your updated code, there is little difference between the two samples. Both maintain proper retain counts. However, it is a "best practice" to avoid using autoRelease unless necessary (especially in a memory sensitive area, like the iPhone). This helps your application to maintain a more predictable and manageable memory footprint.
Yes, the view controller is retained.
There isn't a huge difference between the two code blocks you posted (at least the version I'm looking at -- other people probably saw an earlier version with a misplaced call to autorelease). You could use either one. It's a matter of style.
It sure does. Anytime you give one object to another SDK object like this, it will be retained. Though that second line isn't autoreleasing what you think. Usually you want the autorelease on the same line as the init for clarity sake.
ColorController *colorController = [[[ColorController alloc] initWithNibName:nibColor bundle:nil] autorelease];
[[self navigationController] pushViewController:colorController animated:YES];
If want to try, you should try this
id temp = [self.navigationController.viewControllers objectAtIndex:1];
[self.navigationController popToViewController:temp animated:YES];
you'll be navigated to any other previous ViewController that are available in the stack.
Related
Usually when we push viewcontroller, we will create object for view controller, after that line we will push and release it.
But it gets crashed when we run in iOS5. So I retained the object through propery and declare it in interface as global. Now it is working fine. Will retaining viewcontroller occupy much memory? What is the difference between following two approches?
One:
MyViewCOntroller *obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:obj Animated:YES];
[obj Release]
Two:
self.obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:self.obj Animated:YES];
[self.obj Release]
The first one should be right and please detect for the crash reason again. It can't be crashed when you use the first one to push a new view controller.
As for the difference: in the second one, if you declare the obj as a var of self class and you don't use ARC, you take care of obj like the other instance vars. You just need to do release in the dealloc.
Generally speaking, you should not release property(self.obj) in methods except for dealloc.
The second code snippet should be replaced like this:
self.obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:self.obj Animated:YES];
And add below one to your dealloc method:
self.obj = nil; // Property will release itself and set the point to nil
The first code snippet is OK, you alloced local instance and released it after used.
why aren't you init your view controller with nib?
SearchView *secondViewController = [[SearchView alloc] initWithNibName:#"SearchView" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
be careful with retaining any objects. You must be completely sure that you init it only onse and then release it. If you do so, you may not care about memory. The difference between your inits is: in 1st case you creating ner object. It is NOT retain, but, may be leak, I'm not shure. I think you should add autorelease. In 2nd case you have an object's property (probebly, retain?) in header. you must release it in dealloc method
Are you passing the View Controller to the new Object?
If yes, Are you releasing this View Controller property in the new View Controller's dealloc method? That would be a double release.
Example no. 2 would solve this problem because of the (retain) type property it may have in the old View Controller, would set its retain count to 2.
I have some view controller which I call with the following method:
myViewController *myView = [[myViewController alloc] initWithNibName:nil bundle:nil];
myView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:myView animated:YES];
[myView release];
if I use the app a few times I get a memory warning and the app freezes for a few seconds! I think the reason is that i switch the view but not discharged the old one !!?!!?!!
(i set my outlets to nil and release them)
how can I unload the old view after switching to the new one?
Thanks in advance
When switching the view be sure to call dismissModalViewController:(BOOL)animated on myViewController.
In the class that launch the modalViewController you could make a property for the modal viewcontroller which you retain. Then you could write something like this.
//This would be in an action or something...
if (self.myViewControllerProperty == nil) {
self.myViewControllerProperty = [[[MyViewController alloc] initWithNibName:nil bundle:nil] autorelease];
}
[self presentModalViewController:self.myViewControllerProperty animated:YES];
Then instead of setting the
myView.modalTransitionStyle =
UIModalTransitionStyleCoverVertical;
Move that code to the modalViewController and write self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; I think that looks cleaner, keep the configuration of each viewcontroller separted don't mix it up.
And as the maclema said, call dissmissModalViewController, but you probably are doing that...
Could be any number of problems but you don't need to (and can't) unload the old view. Make sure you are releasing objects and setting outlets to nil in viewDidUnload of all of your view controllers. viewDidUnload will be called when a memory warning occurs so if you don't handle it correctly you'll have leaks and can crash. Other than that, hard to know what else your app is doing that is contributing to the crash.
Part of my code presents a UITableViewController in the following way:
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
flipside = [[UINavigationController alloc] initWithRootViewController:controller];
controller.delegate = self;
flipside.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:flipside animated:YES];
[flipside release];
[controller release];
Using the leaks tools, no memory leaks are picked up on. However, whenever I bring up the settings menu (as shown in the code above), more memory appears to be allocated and never released - almost 100 kB every time.
Weirdly, the inclusion of the two release statements at the end seems to have no effect on the memory allocation..? Is there something I am misunderstanding about memory allocation in objective-c, or is something weird going on?
Any ideas are much appreciated - thanks!
If flipside is a retained property then the navigation controller is leaking. the problem is that you are bypassing the accessor method and releasing flipside directly. This is just messy code. A better way to do it would be to make an accessor method for flipside that will only alloc a new one if you haven't already created one. It's called lazy loading. To do this, just leave the #synthesize for flipside (but you shouldn't set it from outside the accessor method), in your header file change the property to, and add this method to the implementation:
- (UINavigationController *)flipside {
if (flipside != nil) {
return flipside;
}
FlipsideViewController *controller = [[[[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
controller.delegate = self;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
// This implies a retain if your flipside property is set to retain
self.flipside = navController;
[navController release];
}
make sure to put self.flipside = nil in the viewDidUnload method of the view controller the code you included came from (I assume it's a presentSettings action).
what your presentSetting action should now look like is this:
- (IBAction)presentSettings {
// make sure you use the accessor self.flipside instead on accessing the variable directly
[self presentModalViewController:self.flipside animated:YES];
}
I have this code in my app and it says memory leak at 'gvc'.
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
If i modify this code to autorelease view controller, it crashes my app after a while giving error 'Missed Method'
GameViewController* gvc = [[[GameViewController alloc] init] autorelease];
[self.navigationController pushViewController:gvc animated:YES];
Is there something wrong with autorelease? How to resolve this memory leak?
Thanks in advance.
You can safely do this:
GameViewController* gvc = [[[GameViewController alloc] init] autorelease];
[self.navigationController pushViewController:gvc animated:YES];
or this:
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
[gvc release];
They are functionally equivalent and don't cause memory leaks or crashes. Look at your code after [self.navigationController pushViewController:gvc animated:YES]; to see if you over-release gvc.
Just release it when you're all done. If you need it all the time, then put GameViewController *gvc; in the header and put [gvc release]; in the dealloc method.
The obvious solution is simply to release the view controller once you've pushed it onto the nav controller.
i.e.:
GameViewController* gvc = [[GameViewController alloc] init];
[self.navigationController pushViewController:gvc animated:YES];
[gvc release];
That said, I'd be surprised if the autorelease was actually causing a memory leak at all.
It may be everything. I mean, your first code is obviously leaking, and the second code snippet is ok at first glance, but we don't know what you implement inside that class. Imagine in GameViewController, you have a string property userName, and in its dealloc, you do something like:
- (void)dealloc
{
[userName release];
[userName release];
[super dealloc];
}
Then of course it crashes when you release the controller. You should use gdb backtrace (type "bt" when it crashes) to see exactly where it crashes, or better yet, try to enable NSZombie and use instruments to find out.
Btw as a rule of thumbs in iPhone/iPad programming (where resources are scarce), try to avoid autorelease whenever you can.
i am trying to launch a view from a button. When I do it causes a memory link but I can see why.
CamViewController *dvController = [[CamViewController alloc] initWithNibName:#"Cam_View" bundle:[NSBundle mainBundle]];
dvController.camType = 1;
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
any ideas?
The problem is most likely in your CamViewController implementation. If I were to guess, you are creating a bunch of objects in your xib file and they are not getting released in the Controllers dealloc.
It is important to remember that you are responsible for releasing your IBOutlet attached objects in your class.