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.
Related
I dynamically add a subview to another uiview;
in the subview ,click a button to go back by the following method:
[self removeFromSuperView ];
but after manny times added subview and removed it,my app could crash ,the log said it was killed .
I found that calling [self removeFromSuperView] didn't release self. So what's the best methods to releas it?
If you are retaining the UIView on creation (or adding it to an array) the retain count will increase. For example:
// Retain count is 1
UIView *myView = [[UIView alloc] initWithFrame:myFrame];
// Retain count is 2
[myParentView addSubview:myView];
// Retain count is 1 again
[myView removeFromSuperView];
In the above example you can autorelease the view if it is immediately added as a subView or release it in your dealloc if it is an iVar.
EDIT: (other reasons your view could be retained)
// Retain count +1
[myArray addObject:myView];
// Retained in the setter created by the #synthesize directive
#property(nonatomic, retain) UIView *myView;
Anything else that states in the documentation that the property is retained.
You should also be careful of creating objects in the loadView method of a VC, if you do make sure you release them, as they will be created again when the loadView is called. This will happen if you VC's view is unloaded and then reloaded.
u should release at first. counterpart of "alloc" is "release", and counterpart of "addSubview" is "removeFromSuperView":keep those balance.
add view:
UIView *myView = [[UIView alloc] initWithFrame:myFrame];
[myParentView addSubview:myView];
[myView release];
remove view (the view will clear up in memory after removeFromSuperView):
[myView removeFromSuperView];
Looks like you are adding retained view as a subview. Its parent view retains it once again.
So when you cell [self removeFromSuperView]; it gets release message from superView, but still have to be releasd by creator.
I'm struggling a bit with figuring out how to properly set up my view controllers to gracefully handle memory warnings.
At the moment, I'm getting an EXC_BAD_ACCESS crash from a view further back in the navigation controller stack whenever the app receives a memory warning.
The bad access occurs with my table view. Here's how I'm instantiating it:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UITableView *table = [[[UITableView alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.size.width, self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height) style:UITableViewStyleGrouped] autorelease];
table.dataSource = self;
table.delegate = self;
self.tableView = table;
[self.view addSubview:table];
[table release];
...other stuff...
}
And here's my viewDidUnload:
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;
}
Upon a memory warning, viewDidUnload is called, as expected, but I get an EXC_BAD_ACCESS crash on the self.tableView = nil line.
Am I setting up my tableView in the wrong place? I'm not using a nib file, so should I be building it elsewhere? Am I somehow passing it off to the view controller incorrectly? etc etc
Any help would be much appreciated. I still haven't grokked the sequence of events that occurs upon a memory warning, and Level 1 Memory Warnings seem to be obnoxiously common.
You're calling release twice on table; once with a deferred release with autorelease when you're creating it, and again with [table release]; after you've added it as a subview of self.view. Remember, if the property for tableView is 'retain', then it will be retained on assignment (when assigned with dot syntax) -- and, that addSubview will retain table as well when you add it. So, you just need to leave the autorelease in there -- since that deferred release (which will be balanced out by the retain that happens when you say self.tableView = table;.
Try this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UITableView *table = [[[UITableView alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.size.width, self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height) style:UITableViewStyleGrouped] autorelease];
table.dataSource = self;
table.delegate = self;
self.tableView = table;
[self.view addSubview:table];
//[table release]; You have already release table with autorelease.
...other stuff...
}
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.
Should I release my subviews of UIView in the viewDidUnload when I have references to them as instance variables which retains them? I have build the GUI programmatically. I should do that right? Since both uiview and ivars retain then the objects would have 2 in retain-count, when view receives e.g. memory-warning then the UIView will release the subviews, but they still have +1 in retain count so I have to setself.myIvar = nil; In the viewDidUnload?
Thanks for your time.
You actually can release all retained subviews in viewDidUnload. But I used to do it in another way:
-(void) viewDidLoad {
someInstanceView1 = [[UIView alloc] init];
[self.view addSubview: someInstanceView1];
[someInstanceView1 release];
someInstanceView2 = [[UIView alloc] init];
[self.view addSubview: someInstanceView2];
[someInstanceView2 release];
//etc...
//you have a references to someInstanceView1 and someInstanceView2 with retained counts 1
}
In this case even if memory warning will arise, the view controller will remove all it's view subviews. And then call viewDidLoad again. So there would be no leaks and you don't need to care about releasing that ivars at all cause the only owner (it has the strong reference to the views) is the view controller's view and it will release them automatically.
Can anyone explain why viewDidLoad does not get called when loadView is used? It's my understanding that viewDidLoad should still get called.
- (void)loadView
{
CGRect currentFrame = [[UIScreen mainScreen] applicationFrame];
UIView* myView = [[UIView alloc] initWithFrame:CGRectMake(currentFrame.origin.x, currentFrame.origin.y, currentFrame.size.width, currentFrame.size.height)];
myView.backgroundColor = [UIColor redColor];
self.view = myView;
[myView release];
[super loadView];
}
- (void)viewDidLoad {
//this never happens
NSLog(#"VIEW DID LOAD!");
[super viewDidLoad];
}
I've just found out that viewDidLoad won't be called if you call loadView manually in your application.
If you call loadView manually you have to call viewDidLoad manually as well.
More over according to apple docs you shouldn't call [super loadView] as it will overwrite your view with a default UIView.
You must have a warning here:
NSLog("VIEW DID LOAD!");
Instead, you should write like this (the # sign is necessary):
NSLog(#"VIEW DID LOAD!");
viewDidLoad will not get called when you create instance of ViewController. When you are pushing it to navigation controller or present it as model viewcontroller, then only the viewDidLoad get called. Until and unless you are presenting viewController, these delegate will not get called. And one more thing, if your viewcontroller presentation over, and still it remains in the stack or memory, then viewDidLoad method will not get called again because its already load the view. Then viewWillAppear and viewDidAppear delegates only get called when you present the same viewController.