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

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.

Related

iPhone - Loading a new view and a deallocated object

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.

memory release problem

I have created a view and assigned the view to viewcontroller
UIView *newView=[[UIView alloc] initWithFrame:CGRectMake(0,0,320,460)];
in viewDidLoad method I have assigned the view to the viewcontroller
-(void)viewDidLoad{
self.view=newView;
//[view release]; In this case also the application crashing
}
-(void)dealloc{
[newView release];//IN this case also the application crashing.
[super dealloc];
}
The crash log is this.
how to release the newView? or else the viewcontroller itself will take care of releasing the newView.
In most circumstances you will do the following:
- (void) loadView {
// Don't call super here if you assign the view property
UIView *newView = [[UIView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame];
self.view = newView;
[newView release];
// the view is now owned and retained by the UIViewController
}
Apple recommends you allocate the view, assign and release it in -loadView and don't worry about it in -dealloc. This is important in cases when your view may be purged under low memory conditions.

How to delete UIViewController corectly?

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

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.

A white screen is seen when attempting to switch between views!

I wanted to create a very simple method that switches between views in a view based application. For some reason, when the views are switched, the first view is removed and instead of viewing the second view, I see a white screen.
This is my method:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
self.view = firstViewController.view;
[firstViewController.view removeFromSuperview];
[firstViewController release];
secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.view = secondViewController.view;
I don't know why it is happening because I know that the second view's ViewDidLoad method is called (I put a NSLog there) - but the second view is not seen!
Any suggestions?
Thanks in advance,
Sagiftw
viewDidLoad's executing because initWithNibName:bundle: calls it. That doesn't mean that the view's actually being displayed.
I usually use this (removing initialisation/release logic):
[self.view addSubview: firstViewController.view];
[firstViewController.view removeFromSuperview];
[self.view addSubview: secondViewController.view];