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
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.
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.
I'm somewhat unclear on the object ownership patterns required for the following instances. When my UIViewController presents a popover controller, an action sheet, or another view controller as modal, am I required to hang onto a retained reference to that child controller until it's been dismissed?
In other words, do the following lines of code effectively "transfer" ownership, or not?
[aPopoverController presentPopoverFromBarButtonItem:someButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
[anActionSheet showFromBarButtonItem:someButtonItem animated:NO];
[aViewController presentModalViewController:someOtherViewController animated:YES];
Can someone point me to explicit documentation on this subject?
UIPopoverViewController has a slight different memory management/owning. Present a popover does not retain the memory, so you can't transfer the ownership of your popviewcontroller to the presenting object.
To avoid memory leak, you have to adopt the UIPopoverControllerDelegate and implement the DidDismissPopOver method as follow:
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
[popoverController release];
}
This way, you can safe alloc and present a PopOver:
-(void)showSearch:(id)sender {
SearchViewController *searchVC = [[SearchViewController alloc] init];
UIPopoverController *popVC = [[UIPopoverController alloc] initWithContentViewController:searchVC];
popVC.delegate = self;
[popVC setPopoverContentSize:CGSizeMake(320, 100)];
[popVC presentPopoverFromRect:CGRectMake(200, 200, 320, 100) inView:self.view permittedArrowDirections:0 animated:YES];
[searchVC release];
}
Presenting a modal view controller retains the UIViewController. This is actually not clear from the docs. However, I tested it using the following code...
NSLog(#"BEFORE %d", [self.setupViewController retainCount]);
[self.navigationController presentModalViewController:self.setupViewController animated:YES];
NSLog(#"AFTER %d", [self.setupViewController retainCount]);
The self.setupViewController is already retained locally, but presenting it output the following:
2010-05-19 10:07:36.687 LocateMe[27716:207] BEFORE 1
2010-05-19 10:07:36.762 LocateMe[27716:207] AFTER 3
So it is probably being retained in the local modalViewController property, as well as in the view hierarchy. Dismissing it will balance these.
So bottom line is, retain it if you want to control it directly, but you don't have to.
EDIT - Just to be clear, the correct pattern is to always retain an object if you set yourself as its delegate. That's because you should be setting the delegate to nil in your dealloc for safety. Practically though, a modal controller is always going to be dismissed before you dealloc, so it's not an issue. You'll notice Apple also breaks this rule in [UIView setAnimationDelegate:], which actually retains the delegate you set.
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.