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.
Related
I have built a program without a menu. The main view has custom buttons which loads XIBs depending on which button is pressed. The only issue i'm having is when I go back to an already used view, its reset. I have tried "retain" in viewDidUnload and in viewWillUnload. I have tried everything I can thin of and cant get it to work.
- (IBAction)gotoMusicView:(id)sender{
//[self.view addSubview:musicview];
if(self.musicMenuData == nil)
{
musicMenu *musicview = [[musicMenu alloc]initWithNibName:#"musicMenu" bundle:[NSBundle mainBundle]];
self.musicMenuData = musicview;
musicview.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:musicview animated:YES];
[musicview release];
}
musicMenu *musicview = [[musicMenu alloc] initWithNibName:nil bundle:nil];
musicview.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:musicview animated:YES];
}
That musicview loads fine. After I leave that view and go back to the main view, it is RELEASED. Therefore when I reopen "musicview" everything , such as my UIWebView, has reset as if I am opening it again for the 1st time
Create a singleton class using this
And then initialize your .xibs there so you can use the same instance everytime you load the .xib. This way it'll never reset
Instead of allocating and initializing each time you need to use it, keep a reference of all the view controllers you're using, check of its nil on the first time if so initialize, example below.
if(self.someViewController == nil)
self.someViewController = [[ViewController alloc] initWithNibName:#"ViewController"....
//Now present self.someViewController..
Do this for the view controllers that you use for the tabs.
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.
So I feel like a serious rookie right now, but I have a problem I can't seem to figure out. I have a barebones app, with literally nothing in it except a login screen and a second view containing a tableview. When I add the second view after logging in (I have done this like 4 times before...), the table view goes through its delegates and appears that it's going to load, but something happens. I have enabled my NSZombies, and it appears to be deallocating the new view, right before it appears.
After tracing through it, and building up again piece by piece, it appears to happen after I wire the table to the view as the datasource/delegate in IB. I have set the view as a UITableViewDelegate, and the methods indeed get fired. Does anyone have any idea what might be causing this behavior?
Have you added the 'second'view to an exisitng view using addSubview: or added it to some form of UINavigationController or UITabBarController? When you do this it will automatically increase the retain count and whatever code you have releasing the view won't cause is to be deallocated.
In my AppDelegate application:didFinishLaunchingWithOptions I have something like;
LoginViewController *login = [[LoginViewController alloc] init];
[login setDelegate:self];
loginNavController = [[UINavigationController alloc]
initWithRootViewController:login];
[window addSubview:[loginNavController view]];
And then once login has occured (and succeeded using a protocol/delegate to send the message back to AppDelegate) I call this code;
UIViewController *newView1 = [[UIViewController alloc] init];
UIViewController *newView2 = [[UIViewController alloc] init];
UIViewController *newView3 = [[UIViewController alloc] init];
myTabBarController = [[UITabBarController alloc] init];
myNavController = [[UINavigationController alloc]
initWithRootViewController:newView1];
// nav controller now retaining
[newView1 release];
NSArray *viewControllers = [NSArray arrayWithObjects:myNavController,
newView2,
newView3,
nil];
[myTabBarController setViewControllers:viewControllers animated:YES];
[[myTabBarController view] setFrame:[[UIScreen mainScreen] applicationFrame]];
[window addSubview:[tabBarController view]];
// tab bar controller now retaining
[newView2 release];
[newView3 release];
// remove login from application
[[loginNavController view] removeFromSuperview];
The AppDelegate has the following declared in the header file;
LoginViewController *loginViewController;
UITabBarController *myTabBarController;
UINavigationController *myNavController;
In the dealloc method for the AppDelegate these are released.
This gives me my login page and then when that has processed my views with a top nav all controlled using the bottom tab bar.
Hope this helps in some way.
You have either too many release (or autorelease) calls - or not enough retain calls - in your view loading/transitioning code, but it's impossible to be more specific without seeing that code.
What's probably happening is the autorelease pool is being flushed between your view loading and your view being shown, and that's what's leading the behaviour you describe.
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];