Similar to the known memory leak issue regarding creating and destroying an instance of the UIImagePickerController, I'm finding similar problems regarding instances of the UIViewController class. The recommended way to use the UIImagePickerController is to create the instance once and keep it around for the lifetime of the application, eventhough this will use up memory that you may need elsewhere.
The situation I'm dealing with involves 2 instances of the UIViewController class. On start up, the first instance is created and its view is added to another "main" UIViewController class that is part of the MainWindow.xib. On this first instance is an "info" button that when tapped, switches to a new instance of the UIViewController class (if it hasn't already been created). The "main" UIViewController manages this switching with the usual flip animation. The basic setup can be seen in the "Beginning iPhone Development: Exploring the iPhone SDK" book by Dave Mark.
The problem that arises is that once the "info" button is tapped the very first time, memory is allocated to the new second UIViewController instance and it is not released until the application ends. Due to the number of elements on this info view, it uses approximately 1MB of memory once instantiated and its view is added to the superview. Any attempts to consistently destroy and recreate this instance results in a memory leak, similar to the one that exists if you try to do the same thing to instances of the UIImagePickerController class. I suspect that the root cause is the same between the two classes.
The crux of my problem involves needing to have as much memory freed before I allow the user to take a picture with the camera. However, once the user has taken a picture and they see the resulting image the first time through, they are allowed to tap on the "info" button that exists on the first UIViewController instance. Once tapped, the "main" UIViewController removes the existing UIViewController's view and replaces it with the one for the info screen. The info screen has a "back" button to switch the views back. However, once the user leaves the info screen and chooses to take another picture with the camera, the memory allocated to the info screen is still in memory.
The UIImagePickerController class temporarily uses almost 15-18MB while it processes the 2 megapixel image before releasing its internal references and the "imagePickerController:didFinishPickingImage" delegate is called. I am running into low memory alerts once the second UIViewController instance has been created via the info button and then the user chooses to take another picture.
Memory technically is not leaking whether you take pictures over and over with or without tapping on the info button in my case, but due to other issues regarding background processes on the iPhone (Safari, etc.) that are beyond your control, you MUST free up as much memory as possible while working with things like the camera.
Any advice on how to cleanly create and destroy instances of the UIViewController class such that memory does not leak?
The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.
Memory leaks happen when 2 or more objects hold strong references to each other and this causes a retain cycle. Breaking the retain cycle will fix the memory leak. Adding both Instruments and the memory graph debugger to your tool belt can help catchy pesky issues early and often.
A memory leak occurs when allocated memory becomes unreachable and the app can't deallocate it. Allowing an allocated-memory pointer to go out of scope without freeing the memory can cause a memory leak. A retain cycle in your app's object graph can also cause a memory leak.
Are you loading the second view controller from a NIB? If so, you'll want to check that you're releasing the associated memory correctly.
Here's what a typical NIB-based view controller looks like in my projects.
@interface SomeViewController : UIViewController {
UILabel *someLabel;
}
@property (nonatomic, retain) IBOutlet UILabel *someLabel;
@end
@implementation SomeViewController
@synthesize someLabel;
- (void)dealloc {
// Release our retained IBOutlets
self.someLabel = nil;
[super dealloc];
}
@end
One way of reducing your memory usage would be to resize the image to whatever size you want (unless of course you want a 320x480 image). That helped a lot in my case.
Does the second viewcontroller you are talking about change? If not, then it would be best to make it a singleton and use the same instance. You can any time change the values used by the viewcontroller. This article explains how you can create singleton objects (with the code)
Another article here shows the use of a singleton class (though different from your use case, it will clarify how to use singletons)
I would suggest creating a singleton object for UIImagePickerController too.
Do you have any cycles in your chain of ownership? Something like:
@interface FirstViewController: UIViewController {
SecondViewController *secondViewController;
}
@end
@interface SecondViewController: UIViewController {
FirstViewController *firstViewController;
}
@end
If you don't explicitly break this cycle when you discard these view controllers, they'll leak.
Also, I believe you're responsible for releasing all top level objects that are loaded from a nib file when you no longer need them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With