How to delete UIViewController corectly? - iphone

MyPlatesViewController* viewController = [[MyPlatesViewController alloc] initWithNibName:#"MyPlates" bundle:nil ];
[self.view addSubview:viewController.view];
then i delete my viewController
[self.view removeFromSuperview];
but leak instrument shows 20 MB memory
What is wrong ?

You leaked the view controller object. After you remove the view from its superview, you need to release the controller as well.
Alternatively, you can do the following:
[self presentModalViewController:viewController animated:NO];
[viewController release];
Then, when dismissModalViewController is called, both the view and the view controller will be released properly.

You called alloc so it's your responsibility to release it. Your code should look like this:
MyPlatesViewController* viewController = [[MyPlatesViewController alloc] initWithNibName:#"MyPlates" bundle:nil ];
[self.view addSubview:viewController.view];
[viewController release]
Note that your controller is retained by the view when you call addSubview and released when you call removeFromSuperview. So with your current code the retain count of viewController is still 1 after calling removeFromSuperview.
Additionally you should review objective-c memory manament here: http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

Related

Remove subView from View?

I have 2 Views, each View have a ViewController.
I opened the first view early in TabController.
Then (when a line in a table is clicked) I use this to add my subview:
ENSListViewController *vc = [ENSListViewController alloc];
vc.folder_id = 1;
vc.folder_type = #"an";
[vc initWithNibName:#"ENSListViewController" bundle:nil];
[self.view addSubview:vc.view];
[vc release];
In the second view I try to remove this view again, but it ends in a EXC_BAD_ACESS:
- (IBAction)backToFolderList:(id)sender
{
[self.view removeFromSuperview];
}
Where is my mistake?
You are releasing vc by [vc release]; hence it is not getting object of superview..
you have to release it in -dealloc method

transitionFromView:toView:duration:options:completion view memory management?

It doesn't seem like
transitionFromView:toView:duration:options:completion:
Handles memory like it indicates in the Apple docs. It is stated that the fromView is removed from the superview (implying a release) and the toView is added to the superview (implying a retain). Is this correct?
When I transition a view, later in my app when the view is actually presented I will get a BAD_ACCESS as the view was deallocated.
Any ideas? Thanks!
UPDATE:
Here is the code where the problem exists:
UIViewController *container = [[UIViewController alloc] init];
container.view.bounds = [UIScreen mainScreen].bounds;
[container.view setBackgroundColor:[UIColor blackColor]];
/* Deallocated in the finish callback */
tutorialViewController = [[TutorialViewController alloc]
initWithNibName:#"TutorialViewController"
bundle:nil];
tutorialViewController.tutorialDelegate = self;
[tutorialViewController loadTutorialData:data];
UINavigationController *nc = [[UINavigationController alloc]
initWithRootViewController:tutorialViewController];
nc.navigationBar.barStyle = UIBarStyleBlackOpaque;
[UIView transitionFromView:[[window subviews] objectAtIndex:0]
toView:container.view
duration:kAnimationDuration
options:UIViewAnimationOptionTransitionCurlUp
completion:nil];
[container presentModalViewController:nc animated:NO];
[container release];
[nc release];
If I do a [tutorialViewController release] at the bottom of this method, I will get the BAD_ACCESS. So it seems like the UINavigationController does not retain the root view controller.
P.S. The tutorialViewController was not a member variable previously, but I have now fixed this problem by simply releasing it after the view has been dismissed.
You should check and confirm that you are not releasing the view yourself, hereby over-releasing. Or perhaps check the dealloc method for the view class which is being released to see if you're over-releasing anything in it.
The answer, after much testing, is simply that UINavigationViewController does not retain the view with initWithRootViewController. The Apple docs aren't clear on this.

PresentModalViewController: Where to release?

To use presentModalViewController I must alloc and initWithNibName:bundle: a view. My question is: where do I release it? Does the dismissModalViewController:animated: handle the release?
No. If you allocatet and initialized it, than you have to release it. Do it like this:
YourViewController *controller = [[YourViewController alloc] initWithNibName:#"YourView" bundle:nil];
[self presentModalViewController:controller animated:YES];
[controller release];
PresentModalViewController:animated: increases automatically the retainCount. And as soon as the controller disappeared from the view, it will release the controller. And so the controller will be deallocated. ;-)
You can release after you present the controller; the presenting controller (its parent) will retain your modal controller.

is this lead to memory leak for iphone

Let me explain in detais
In appDidfinish()
{
preLoginNavController = [[PreLoginNavController alloc] initPreLoginNavController];
[window addSubview:[preLoginNavController view]];
}
then in preLoginViewController when user press a button
then i am doing this to go to view2
RootViewController *arootController= [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:arootController animated:YES];
if i do this [arootController release]; then i cant come form view 2
now in view 2 when back button is pressed
then i am doing this
[self.navigationController popToRootViewControllerAnimated:YES];
so i cannot release [arootController release] else when i go to back view app quits with no error
and i need a prelogin view before Rootview thats why i did like that now what should i do .. my app is working fine but i want to fix that leak :(
HEY
i am getting this message when i click back button in view 2 after push and release in preLogin(1st view)
objc[408]: FREED(id): message release sent to freed object=0x466a340
I think yes, is leaking arootController once you pop it.
yeah, there will have a leak. 2 suggested solutions are:
[arootController autorelease];
or after you do :
[self.navigationController pushViewController:arootController animated:YES];
you can release it.
A good practice is that : who increase the retain Count, should decrease it. and because aRootController is init in that class, it should be released there
Edit:
This should be the correct code if you want to use navigationController:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.preLoginNavController = [[[PreLoginNavController alloc] init] autorelease];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.mainItemListViewController];
[window addSubview:[self.navigationController view]];
[window makeKeyAndVisible];
}
then when you need to push:
[self.navigationController pushViewController:anotherViewController animated:YES];

Retain/release pattern for UIPopoverController, UIActionSheet, and modal 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.