As the following code :
UIViewController *controller = [[UIViewController alloc] init];
[controller.view addSubView:myOtherController.view];
[self.navigationController pushViewController:controller];
[controller release];
And myOtherController is a global object, it will not be released.
So the question is that when the controller is popped, if it will be released?
And If it will not be released, how can I verify this?
Thank you!
It will be released when popped. UINavigationController retains pushed view controllers and, of course, releases them when popped.
Edit: Object ownership is a directed association—but not a tree: Object A owns object B while B can be owned by any number of other objects.
The popped controller owns its view which, in turn, owns the subview. When the popped controller is deallocated it releases its view which releases the shared subview. The shared subview is still owned by some other object so it's not deallocated.
That's the idea of reference counting.
Related
Here's what i did.
Make a clean OSX project.
went to main.xib and dragged a popover controller. This created 2 visible objects on on interface builder.
I went to the appDelegate.h file and did
`-#Property (assign) IBOutlet NSViewController *popVC;
Then i went to the applicationDidFinishLaunching: method and did
popVC = [[NSViewController alloc] init];
Result: I get the following error message:
Shouldnt objects on a nib be weak since it is already owned by the nib?
Outlets to view controllers should be strong. The NIB doesn't own the objects, its just an archive. Outlets to views should usually be weak but that's because the view is retained by its superview (the superview is usually retained by its view controller).
As an aside, you shouldn't be doing:
popVC = [[NSViewController alloc] init];
Because popVC is being unarchived, created and set when the NIB is loaded. By creating and setting an instance yourself you're throwing the NIB version away. This applies to all outlets - the purpose of an outlet I'd to be filled in when a NIB is loaded.
I have a UINavigationController object (named LoginNav) which consists of ViewController1 & ViewController2, my iPad app starts by loading a UISplitViewController subclass (named mainSplitViewController) and then presenting LoginNav modally on top of it (this is by the way done in didFinishLaunchingWithOptions method of AppDelegate like this:
[self.mainSplitViewController presentModalViewController:LoginNav animated:YES];).
Once ViewController1 is shown, I tap a UIButton in it to push ViewController2, when I finish working in ViewController2 I tap a UIButton in it to call [self.navigationController dismissModalViewControllerAnimated:YES]; to dismiss LoginNav with both of its view controllers and show mainSplitViewController's contents.
There is a dealloc method in both ViewController1 & ViewController2 with NSLog statement in each one, once loginNav is dismissed, the NSLogs never get fired, but doing [self.navigationController.viewControllers objectAtIndex:0] release]; & [self.navigationController.viewControllers objectAtIndex:1] release]; right after [self.navigationController dismissModalViewControllerAnimated:YES]; fires both NSLogs.
I commented out the above two release statements, then I launched the Allocations instrument, and launched the app again and pushed ViewController2 then dismissed loginNav as described above, and looked at Live Bytes column (All Allocations value ) it was 6.9 MB right after the dismissal of loginNav, then I did this step again but in this case using the two release statements, I got exactly a 6.9 MB value on Live Bytes column.
Two Questions:
1) why do not the dealloc methods of ViewController1 & ViewController2 never get fired after the dismissal of the navigation controller LoginNav that holds them ? and is it correct to do the above two release statements to release these view controllers ?
2) why releasing ViewController1 & ViewController2 does not free up memory ?
p.s. there is no single variable (or IBOutlet) being held in memory in both ViewController1 & ViewController2, everything is released in both of them.
These kinds of issues are nearly impossible to troubleshoot without seeing all your code. When you manage memory manually, there are multiple areas that you can go wrong. For example the following code will leak:
- (void)didSelectSomethingInViewControllerOne
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[self.navigationController pushViewController:vc2 animated:YES];
}
In this case you have allocated the object and thus have ownership of it. Then the nav controller takes ownership of it. When you pop the controller from the navigation stack, the navigation controller relinquishes ownership of it, but you never did, so it still has a retain count of 1 and won't get deallocated.
Relinquishing ownership of the controllers later in your code (like after dismissing the modal view) is a bad idea. It makes it difficult to analyze ownership when your releases are all over the place. As soon as the navigation controller has ownership you can release the object you allocated, as you do not intend to use it in the future:
- (void)didSelectSomethingInViewControllerOne
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[self.navigationController pushViewController:vc2 animated:YES];
[vc2 release];
}
The situation above can have nothing to do with your problem. Your problem may reside in many different areas. Which is why troubleshooting memory management problems is difficult. Without seeing source code.
Consider transitioning your project to ARC:
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
Another thing you might have fallen foul of is a retained property (such as a delegate) in your LoginNav.
I was just wondering while programming. I have got a rootViewController which creates an instance of a childViewController. This childVC is pushed onto my rootViewController through [self.navigationController pushViewController:childVC] from another childViewController (say childVC2). Now I was wondering what happens with my instance of childVC2. Does it get released? Because when returning from childVC to childVC2 I create a new instance of childVC2 and push it into my rootViewController. Obviously I do not have any use for the earlier instance of childVC2 so what happens with it or haw can I manually release it?
Yes if you are alloc the ViewController you have to release it .. the push will increase its reference count by 1 so you have to be sure that you are pop it to decrase the reference count .. and for the creating the instance define it in .h and when create it do it like this
if(yourViewController)
[yourViewContoller release];
yourViewController = [yourViewControllerClass alloc] init];
another opition is to make it autorelease and in this case you are not responsible to release the ViewController
yourViewController = [yourViewControllerClass alloc] init]autorelease];
I have a BaseViewController, which is a subclass of UITabBarController, and set up my views in this view controller.
-(void)setUpViews
{
FirstController *mainViewController = [[FirstController alloc] initAssignment:delegate.currentAssignment withMutableArray:myArray];
UINavigationController *firstNavController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
SecondController *secondViewController = [[SecondController alloc] initWithNibName:#"SecondController" bundle:nil];
UINavigationController *secondNavController = [[UINavigationController alloc] initWithRootViewController:secondViewController];
self.viewControllers = [NSArray arrayWithObjects:firstNavController, secondNavController,nil];
firstNavController.tabBarItem.image = [UIImage imageNamed:#"blablabla.png"];
firstNavController.tabBarItem.title = #"Stream";
secondViewController.tabBarItem.image = [UIImage imageNamed:#"blabla.png"];
secondViewController.tabBarItem.title = #"Favourite";
}
Now I have another view controller, I call it ViewHandlerController, a subclass of BaseViewController. in my viewDidLoad in this viewHandler, i invoke setUpViews which is declared in BaseViewController. in the first screen of my app, when a Login button is pressed, I instantiate my ViewHandlerController, and presented my tabcontroller succesfully with nav controllers by using.
[[[UIApplication sharedApplication].windows objectAtIndex:0] addSubview:viewControllerHandler.view];
Inside my app. there is a logout button. I am using NSNotificationCenter to call my logoutMethod which is declared in my first screen. My question is, in this logoutMethod, how can I release the previously allocated objects to avoid memory pressure since the user can log in again (logIn - logOut -logIn)? since I'm using ARC, is setting my ViewController to NIL will do all the clean up?
EDIT: is removing my ViewControllerHandler from superview and setting it to nil helps releasing its subviews too?
Cheers
Well, answer for your question (not ARC) – no, basicaly view controller doesn't releases his properties when release. But you should nil your properties in viewDidUnload and (or) dealloc methods.
If you use ARC, you should notice that some actions can retain your controller, and it can never be deleted in some cases. Watch for methods, which takes object for delegate, they may not using weak references
Have a look at this Apple article about memory management.
You can just use autorelease in alloc methods or for (UIView *view in [self.view subviews]) {view release}; in dealloc.
In fact release is opposite operation to retain. When you do retain, you increase by 1 count of object instances in allocated memory. It happens when you call alloc, copy, new, mutableCopy. If you are using ARC you can't release objects, memory management is not your problem already.
I have one root viewcontroller loaded by app delegate and a second one (no nib file) that should be loaded as root controller's child (i want to display its view contained in root controller's view).
Where and how should i do this? Is viewDidLoad method suitable for such initialization?
- (void)viewDidLoad {
MyViewController* pdfController = [[MyViewController alloc]init];
[self.view addSubview:pdfController.view];
[super viewDidLoad]; }
What about releasing such an object? Should I release it in dealloc or viewDidUnload or both? where viewDidUnload/dealloc will be called?
viewDidLoad is an okay place to add your child view to the root view. You should release it at the end of viewDidLoad; pdfController will be going out of scope (so you'll be losing track of the object) and [UIView addSubview:] will retain it. If you were also keeping a reference to pdfController in an object property, you would want to release it in dealloc for that object.