Whenever I add a new viewController my ObjectAlloc jumps up really high and never comes back down. Even after calling removeFromSuperview. Is this normal?
if((UIButton *) sender == gameArcadeBtn) {
GameArcade *gameArcadeController = [[GameArcade alloc]
initWithNibName:#"GameArcade" bundle:nil];
self.gameArcade = gameArcadeController;
[gameArcadeController release];
[self.view insertSubview:gameArcadeController.view atIndex:1];
}
Instantiating a view always creates many objects.As long as this view is in memory or has not been autoreleased, the objects will remained alloced in memory. Thus, to answer your question, this is normal.
It sounds like you are worried about memory usage and while it is important to watch the object allocs so that it doesn't get too it is more important to find your app leaks.
Some memory management tips:
1) do lazy loading. Only load your views when the user asks for them, not all at the beginning of the app
2) remove everything that you possibly can when you dont need it anymore. This means doing tons of work in viewWillAppear and viewDidDisappear
3) learn about #properties and how it relates to autoreleasing, and do not use properties for everything.
4) As appealing as it is, avoid autorelease and manually release objects when you dont need them anymore.
that's probably due to the fact that you're still retaining the view's controller in the class. try releasing that
Related
I am a former java programmer, and I am having some troubles managing the memory on cocoa touch.
In fact, I think I got the retain/release trick, but still I am not sure I got it right.
For example, I am creating and adding a subview to the main window:
aViewController=[[AViewController alloc]init];//aViewController is (nonatimic,assign), so retaincount = 1 after this line?
[self.window addsubview aViewController];
[aViewController release];//retaincount=0?
And in aViewController I have an IBAction:
[self.view removeFromSuperView];
How can I be sure the object aViewController gets completely 'deleted' and memory released after I removed it from superview (think that controller as a graphic-heavy view controller)?
Also, generally, is there a way to be sure an object is deallocated? I am aware that if I ask ownership of an object I have to release it at a certain point, but what if I just want the object's pointer to be null at a certain point(not basing on the retaincount)? Should I call dealloc directly? I find sometimes very confusing to keep under control the retain/release mechanism.
If someone could give me a quick breakdown to make my mind 'click', i would be extremely grateful.
Thanks.
The short answer is you shouldn't worry about when an object gets deallocated (unless you are debugging a memory management problem). You should just worry about ensuring that if your code retains, copies or inits an object, it releases or autoreleases it. By doing so you will ensure reference counts are properly maintained and hence deallocation will be managed for you.
Leave the task of deciding when to dealloc an object to the runtime. Never call dealloc directly unless you are calling the super classes dealloc method at the end of your objects dealloc method.
Also, don't even look at the retain count property of an object. Various pieces of the framework manipulate those too during the lifetime of the object, and you'll see that number move around seemingly at random. It'll just drive you nuts.
The really important thing is to make sure you've got the objects retained that would be a problem if they went away suddenly, and released when you're okay with them going away suddenly.
aViewController=[[AViewController alloc]init];retainCount is 1
[self.window addsubview aViewController.view];retainCount is 2 (adding the view increments the retainCount)
[aViewController release];retain count decrements to 1;
[aViewController removeFromSuperView];retain count decrements to 0;
Now the dealloc method will be called the allocated memory will be freed. This is what have understood please correct me if i am wrong i always find difficulties during memory management.
When the user taps on the right callout accessory on my map view's pin's callout I am showing a popovercontroller with a view inside it. I am maintaining 2 retained properties in the mapcontroller for this. I am also releasing these properties in dealloc of the mapcontroller - which probably never happens.
When the user deselects the annotation view I want all this memory released, does assigning nil suffice?
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
[self.informationViewController.view removeFromSuperview]; //remove from popovercontroller
self.informationViewController = nil;
popoverController = nil;
}
Yes, it should. This sets the reference of the object to nil which in turn releases the object. I'm no expert on memory management though, so if anyone wants to downvote/correct me, feel free.
I believe you also will need to release the objects.
Wouldn't just assigning nil only remove your pointer to the object in memory? I suspect the object would still reside in memory and still have a retain counter assigned to it, so it will not be removed from memory until it's retain count was decremented.
Further, by assigning your pointer to nil before you released the object, I also would suspect that you will have created a memory leak because the attempt to call release in the dealloc of the controller will not actually release the object.
I'm not 100% sure about this, but ... here is also a link to the Memory Management Programming Guide.
Also, for the future, if you want to be sure, you could run your application using the Leaks performance tool, it should show you where you're leaking memory and what objects are currently allocated in memory, etc...
I could try to setup the scenario in a test project real quick and monitor it using Leaks and update my answer later also.
I recently changed my app to use a UINavigationController, I was using a UINavigationBar before, with cascade subView adding, which was a bit tenuous.
I'm facing a problem of memory usage. Leaks tool doesn't show any leak, but ViewControllers I create and add to the UINavigationController never seem to be released. So memory usage grows everytime I create a new VC and then press the NavigationController's back button.
I simply create and add my VCs this way:
DetailViewController* detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// setups
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
The app never goes through ViewController's dealloc and viewDidUnload methods. Shouldn't these be called everytime I press the back button?
I've searched many tutorials and read Apple's memory management, but there's nothing about VC's lifetime in memory when using NavigationController.
Maybe you are not doing something wrong and instead you are facing something like this
In the Blog post it was the question whether we have to manually release IBOutlets or not. As it turns out we should. This was reproduceable in iOS 3.1.3 but I didn't test it in iOS 4.0 yet.
The second aproach is to override your view controllers retain and release method and print out the retain count. I had a simimlar problem, that some view controllers dealloc method did not called so I override this methods to see wether someone has still a retain on it. As it turns out it did.
Edit:
When I printed my retain count, it would sometimes reach ~98 caused from the framework, so thats not really to worry.
If your last retain count stays at 2 and the dealloc method won't be called, than there is someone that has still a retain on it.
In this case you should search on other places.
For example another problem I encountered during this same problem:
Sometimes I would use
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateUI) userInfo:nil repeats:YES]
to constantly update the UI. But what I forgot was, that the NSTimer will retain the target object (which was the ViewController). Because the NSTimer retained your view controller your dealloc will never be called because someone (NSTimer) has still a retain on it. So you have to make sure to invalidate the NSTimer BEFORE dealloc method to properly release the view controller.
Edit2 in response for a comment below:
A retain declaired property does as follows (exsample):
- (void)setTarget:(id)value {
if (value != target) {
[target release];
target = [value retain];
}
So it does first release your current self.target then retains the new value. Since you are assigning nil your target will be nil afterwards. Further info about Properties can be found in the Apple doc.
I have seen this as well. As you pointed out, I haven't seen anything definitive in the docs, but my belief is that they are retained in memory until memory is needed. It makes sense from a performance perspective as doing so allows the app to quickly navigate between the different views.
Bottom line is, I wouldn't worry about it. You could fire off some Low Memory Warnings in the Simulator and see if it actually releases your VCs.
I'm writing iPhone application which uses multiple views, each with own controller. They are loaded programmatically using initWithNibName: and released before switching to other controller, so only one view is visible at a time.
After releasing view controller (I have checked that dealloc is called) not all memory is freed. I do release all outlets when deleting controller. Also, setting self.view to nil in controller's dealloc doesn't solve the issue. Memory consumption gets bigger though Leaks from instruments doesn't show any leaks.
Is there any way to completely remove those views with their controllers from memory? I want to have the same free memory amount before new controller is created and after it is deleted.
You can override retain and release on any class, to get a better understanding of when the retain count gets higher than you might have expected.
Something like this:
- (id) retain
{
NSLog(#"Retain: Retain count is now %d", self.retainCount+1);
return [super retain];
}
- (void) release
{
NSLog(#"Release: Retain count is now %d", self.retainCount-1);
[super release];
}
When that is said, I think you have to check that your "memory leak" is not just something the system has cached. If you can consistently use more memory by doing the same sequence again and again, then you have a leak.
Problem is solved now, it was UIWebView. It kept some cache and there was no way to clear it. After replacing UIWebView with UIScrollView (it was used to show simple local page) problem is gone.
what are best pratices to reuse UIViewControllers? In many apps (including Apple's own examples: e.g. SQLiteBooks), UIViewControllers are allocated and initialized everytime, a UIViewController is pushed to the stack. This increases the use of memory with every new controller, because the objects stay in memory and aren't used again.
How to make it better?
This increases the use of memory with
every new controller, because the
objects stays in the memory and aren't
used again.
It should be released when the stack is popped though, as long as you have not got something else holding on to it. Check your dealloc methods are getting called.
Also if it is pushed to the stack, then you need to keep it around at least until it is popped (which automatically happens if you follow the standard patterns). So it is used again.
So following the standard pattern should already keep your memory usage as small as you can get away with.
This is what I do when creating a new viewcontroller and the memory is released when the view is removed from the window
MyViewController *mvc = [[[MyViewController alloc] initWithNibName:#"MyView" bundle:nil] autorelease];
[[self navigationController] pushViewController:mvc animated:YES];
Do you actually have a memory issue that you are trying to address or is this a case of premature optimization? I would say that unless there is a specific resource issue then the best practice would be to follow the standard view controller patterns.
Put a breakpoint in your view controller's dealloc function, and make sure it is called when you remove the view controller from the window. The memory shouldn't keep building up. If you're properly creating and autoreleasing your controllers (as LostInTransit shows above), the memory for each controller should be released when it is removed.
If you see that dealloc is not getting called, it means that somewhere in the app a reference to the view controller still exists.
Don't forget that a View Controller is not your view.
Views held by a view controller can unload, so view controllers themselves are very lightweight. If you want to keep the footprint really light you could nullify any other data the controller has allocated in viewDidUnload (mostly called when there's a memory warning - it's a 3.0 only thing though).
As noted mostly view controllers will be deallocated when you leave them (hit back) so there aren't generally that any hanging around anyway. But sometimes I find it handy to leave a reference around if I want to re-open that view in the same state the user left it (does not work between app launches).