I have some pretty simple code where I am using a UINavigationController and adding a rootViewController. After some processing has occurred I want to pop off the current view controller and replace it with another one. This seems to work fine, but my original view controller does not dealloc. I set a breakpoint in it's dealloc and it never gets hit. Below is my code. Not sure why happens. Just for testing if I release startController twice it does go away.
StartViewController *startController = [[StartViewController alloc] initWithNibName:#"StartViewController" bundle:[NSBundle mainBundle]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:startController];
[nav pushViewController:startController animated:NO];
self.navController = nav;
[startController release];
[nav release];
Thanks any help.
Your ultimate goal is to bring the view controller's retain count to zero. So make sure that everything the view retains is released and anywhere the view is retained also release.
Please check the following possible causes:
Make sure you pop the view controller from the navController if you have a custom back button. The default Back button will work fine.
Make sure that all your IBOutlets are set to nil in viewDidUnload
- (void)viewDidUnload
{
[super viewDidUnload];
self.webView = nil;
}
If your view is an observer to a model class to receive events
For example
model.addObserver(myView);
and sure to also do
model.removeObserver(myView);
I hope this helps.
It looks as though your self.navController has got a holding reference to it. maybe put
self.navController =nil;
somewhere appropriate, so that when the view has been popped it is released.
I was trying to pop off the root view controller. I instead used the setViewControllers message from the UINavigationController object to replace all my view controllers.
Related
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.
recently I joined two Xcode projects together. To get this thing to work, I had to alloc and initialize my view controller.
self.myViewController = [[MyViewController alloc] init];
But why? In the other project I have the same code. The sole difference is hierarchy of the different views. I added a new view to the top (beginning). So the calling View Controller is not the first view on the stack anymore.
I'm pushing my view in this way on the stack:
[[self navigationController] pushViewController:myViewController animated:YES];
In my NIBs I have added a View Controller object with IB and connected the Outlets.
And I have a memory management question too: If I have a property like myViewController, do I have to release it? The "normal" release is done in the dealloc method. But do I have to use an additional release because of the alloc? I don't think so, but I ask you anyway.
I would need to see more code to answer why you had to alloc your view controller, but I'd say that you always alloc them manually (at least in my experience).
As for the memory management question, if your property is declared as a retain property (#property(retain) UIViewController *myViewController), you are indeed leaking memory, since the retain count after alloc will be 1, and after the retain done by your accessor will be 2. Hence, if you release it only once, you'll end up with a leak.
I usually do this instead:
self.myViewController = [[[MyViewController alloc] init] autorelease];
I found it out: In IB I had to set the nib name on my view controller object. So the alloc and initialization is done by IB?
There is one more option:
(IBAction)loginButton:(UIButton *)sender {
NSLog(#"pressed login");
ICMasterViewController *controller = [[self storyboard] instantiateViewControllerWithIdentifier:#"mainnav"];
[self presentViewController:controller animated:YES completion:nil];
}
On your storyboard you must have UIViewController with name mainnav
In order to speed up my app, I've create three different UIViewController in AppDelegate and it has readonly property for the controllers. Those controllers are used for navigation controller.
If I tap a button on the root view, I just show another view using pushViewController method. Let me show you some code for this here.
UIViewController* controller = delegate.anotherViewController;
[delegate.navigationController pushViewController:controller animated:YES];
At first time, this work well, but if I navigate back and tap the button again, I've got a signal 'EXC_BAD_ACCESS' at second line.
What's wrong? And, how can I prepare all of my view controllers at the beginning, not create them when they are needed?
Most of the time EXC_BAD_ACCESS means that you've released an object and you're trying to reuse it without retaining it.
Look if you have released your viewController too early and whether you are (re)using it the right way or not...
I had the same problem. My code was
AddMedia *info = [[AddMedia alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:info animated:YES];
[info release];
I was releasing my viewCOntroller which was crashing the app.
When I commented that line, It worked seamlessly. The code after the change is:
AddMedia *info = [[AddMedia alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:info animated:YES];
// [info release];
I'm new to iPhone development and am having problems removing a sub-view from the main window. The problem is that the view still shows up even after calling removeFromSuperview.
The sub-view is created and added to the display tree through this code:
// Instantiate the controller for the authentication view
AuthenticationController* controller = [AuthenticationController alloc];
[controller initWithNibName:#"AuthenticationView" bundle:[NSBundle mainBundle]];
authController = controller;
// Add the authentication view to the window
[[stateManager appWindow] addSubview:[authController view]];
Then later, and I have verified that this code is run by setting a breakpoint, this is how I'm attempting to remove the view:
[[authController view] removeFromSuperview];
In case it matters, here's the dealloc code that does the for the owner of the view controller:
- (void)dealloc {
[authController release];
[super dealloc];
}
What is causing this sub-view to continue to show up?
I got this working. Apparently, a view doesn't go away until it's deallocated, and I had a misunderstanding of how memory management works on this platform. Here's my corrected code:
AuthenticationController* controller = [[AuthenticationController alloc]
initWithNibName:#"AuthenticationView" bundle:[NSBundle mainBundle]];
controller.delegate = self;
authController = controller;
[controller release]; // <-- Problem was that a reference was being maintained
[[stateManager appWindow] addSubview:[authController view]];
Not sure what you mean by "show up." On screen? In memory?
Your "fix" looks buggy, in that alloc gives you one reference, you then release it, which gets rid of the AuthenticationController. Which you then use.
This might appear to work since there hasn't been anyone overwriting the controller before you read its view, but this is just asking for trouble.
I ran into a situation that seems to suggest otherwise. In the following code snippet, if I remove the line: self.navigationController = nav, the root controller's view won't show up, suggesting to me that addSubview might not actually retain the view as otherwise suggested. Any idea?
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.testViewController = [[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.testViewController];
self.navigationController = nav; //<-- if this line is removed, test view won't show up
[window addSubview:nav.view];
[nav release];
}
This line:
[window addSubview:nav.view];
does NOT add a view to the screen immediately. It is displayed by the OS in some future run loop on a possibly different thread. The actual implementation we can't be sure of.
This is why Apple defines delegate methods like viewDidAppear/viewWillAppear, otherwise we would not need them as we would know precisely when these events occur.
Moreover, adding a subview as you said, does indeed retains the view. It does NOT however retain the view controller or the navigation controller. Since the navigation controller WILL retain any added view controllers, we do not have to back them with an ivar.
But, your reference to the navigation controller must persist beyond the scope of the method. or depending on your code it could be dealloc-ed or have its reference lost.
So you must keep a reference to the navigation controller with an ivar and set it like so:
self.navigationController = nav;
So even though nav.view contains a pointer to testViewController.view, the application has no reference the navigation controller and, by extension, the view. The result is a blank screen.
To make this more obvious that it isn't a retain/release problem, you are actually leaking in the following method:
self.testViewController = [[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]];
You need to autorelease to balance out your retain/releases by:
self.testViewController = [[[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]] autorelease];
So, that means your view has never, ever been deallocated any time you have ran this code. Which further assures us that your issue is indeed a lost reference.
The problem probably isn't that the view isn't retained, it's that the controller isn't retained.
Without this line:
self.navigationController = nav
Nothing is retaining the navigation controller. It would be strange to have the view outlive the controller.
This doesn't look lika a retain/release question to me. You view won't show up if you comment out self.navigationController = nav; because then in the next line, [window addSubview:self.navigationController.view] your self.navigationController property won't be set. It's probably nil or it would crash but can't say for sure without more of the code.