uiimagepickerview controller creating memory leaks in iphone - why?
Try to implement ui image picker view controller in your application & debug it.
You will find memory leaks in your application.
Why ui image picker view controller creates memory leaks.
-(void)addPhotos:(id)sender
{
if(imagePickerController==nil){
imagePickerController=[[UIImagePickerController alloc]init];
imagePickerController.delegate=self;
imagePickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.allowsImageEditing=YES;
imagePickerController.navigationBar.barStyle=UIBarStyleBlackOpaque;
}
[self.navigationController presentModalViewController:imagePickerController animated:YES];
}
dealloc of my view controller.
- (void)dealloc {
if(PhotoDateArray!=nil)[PhotoDateArray release];
if(imagePickerController!=nil) [imagePickerController release];
if(objDetail!=nil) [objDetail release];
if(Picimage!=nil) [Picimage release];
if(mySavePhotoController!=nil) [mySavePhotoController release];
if(LoadingAlert!=nil);
[super dealloc];
}
Video link explaining how I am getting the memory leak in it..
http://www.yourfilelink.com/get.php?fid=508534
Even though you have the nil check, it's still possible to leak memory. I think what is happening here is that you are calling alloc / init multiple times, but only releasing once. My guess it that addPhoto: is wired up to some button click, dealloc would only be called once when the delegate is trying to destroy. This creates a situation like this:
button click
alloc / init
button click
alloc / init (memory leak on first alloc'd picker)
close window
dealloc (free second alloc'd picker)
A better way might be the way Apple does it in the PhotoLocations and iPhoneCoreDataRecipes examples:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
Then listen for the didFinishPickingImage and imagePickerControllerDidCancel messages to your delegate and a call to [self dismissModalViewControllerAnimated:YES]; in both places should suffice.
I dont know about the rest of the code, but do you ever have a release?
[imagePickerController release]
UIImagePickerController loads and initializes PhotoLibrary.framework the first time it is shown. This memory won't be reclaimed until your application is closed.
(the code you posted doesn't appear to have leaks as-is, but that doesn't mean it won't interact with the rest of your application in a way that causes them)
I can explain this because I was having the same problem.
Don't test memory on the simulator!
If you test the apple code on a device the memory problem disappears.
I was having a memory alloc leak which I found in Instruments. All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code, just like yours above.
All were showing the allocation going up and up each time, as if the picker was not being released. If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device. Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job.
I want to add this to save people, the time, pain and bewilderment of wondering wtf is going on!
Related
I am seeing a huge memory leak when using UIImagePickerController in my iPhone app. I am using standard code from the apple documents to implement the control:
UIImagePickerController* imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
switch (buttonIndex) {
case 0:
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:imagePickerController animated:YES];
break;
case 1:
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:imagePickerController animated:YES];
break;
default:
break;
}
}
And for the cancel:
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
The didFinishPickingMediaWithInfo callback is just as stanard, although I do not even have to pick anything to cause the leak.
Here is what I see in instruments when all I do is open the UIImagePickerController, pick photo library, and press cancel, repeatedly. As you can see the memory keeps growing, and eventually this causes my iPhone app to slow down tremendously.
As you can see I opened the image picker 24 times, and each time it malloc'd 128kb which was never released. Basically 3mb out of my total 6mb is never released.
This memory stays leaked no matter what I do. Even after navigating away from the current controller, is remains the same. I have also implemented the picker control as a singleton with the same results.
Here is what I see when I drill down into those two lines:
Any help here would be greatly appreciated! Again, I do not even have to choose an image. All I do is present the controller, and press cancel.
Update 1
I downloaded and ran apple's example of using the UIIMagePickerController and I see the same leak happening there when running instruments (both in simulator and on the phone).
http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html%23//apple_ref/doc/uid/DTS40010196
All you have to do is hit the photo library button and hit cancel over and over, you'll see the memory keep growing.
Any ideas?
Update 2
I only see this problem when viewing the photo library. I can choose take photo, and open and close that one over and over, without a leak.
It's a bug in the SDK. File a report with Apple. I have the samme isue. It is also documented here: http://www.cocoabuilder.com/archive/cocoa/285293-iphone-memory-leak-can-explain.html
and that was over a year ago and still no fix.
A few of our apps reuse the same UIImagePickerController due to a leak in 2.x (it makes me feel old...). I was under the impression that the leak was fixed, but I could be wrong.
It's a slightly horrible workaround, but sometimes that's the best you can do.
Try setting the UIImagePickerController.delegate to nil before releasing.
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
picker.delegate = nil;
[picker release];
}
The "Mark Heap" button in Instruments has been, for me, the absolute best way of tracking down these sorts of issues.
This is an OK article on how to use it: http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
But it will tell you, for sure, which objects are surviving longer than you expect... and, ultimately, what the source of the issue is.
You can also see a complete retain/release trace for each individual object which survived - allowing you to pinpoint where your problem is.
EDIT: I use a UIImagePickerControllers as well, and I can promise it doesn't leak (at lesat for me) the way you're suggesting - so, whatever is going on, it's almost surely fixable.
I used UIImagePickerController and after 40 capture images my application received a DidMemoryWarning message and stop, hidden all my views.
In my application I create 40 objects of
UIImagePickerController( new UIImagePickerController() )
To work correctly I create a unique instance shared to all application and with this all work correctly.
I supusose that control lost memory too, but only one time. My application can capture images from camera correctly:
private static UIImagePickerController picker = new UIImagePickerController();
i have found leaks in the below code at particular area, means when i push my view from other sides, There is not any leak i found but only this push give me 100%leak.
actionsListing *View = [[actionsListing alloc] init];
[self.navigationController pushViewController:View animated:YES];
[View release];
What will i do thanks.
That code is fine - you're doing everything correctly.
Are you testing in the simulator or on a device? If it's the simualtor, don't. The simulator has a different memory model and reports leaks that aren't really there; always test for leaks on a device :)
If you still get leaks, you're retaining the view controller somewhere else by mistake - that code is definitely correct.
This is driving me crazy!!!
I'm getting a "Received memory warning. Level=1" whenever I attempt to show a UIImagePickerController with a sourceType = UIImagePickerControllerSourceTypeCamera.
Here is the code from my viewDidLoad where I set things up:
- (void)viewDidLoad {
[super viewDidLoad];
// Set card table green felt background
self.view.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"green_felt_bg.jpg"]];
// Init UIImagePickerController
// Instantiate a UIImagePickerController for use throughout app and set delegate
self.playerImagePicker = [[UIImagePickerController alloc] init];
self.playerImagePicker.delegate = self;
self.playerImagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
And here is how I present it modally ..
- (IBAction) addPlayers: (id)sender{
[self presentModalViewController:self.playerImagePicker animated:YES];
}
The result ... UIImagePicker starts to show and then boom ... I get the memory warning ... EVERY TIME! Interestingly enough, if I switch to sourceType = UIImagePickerControllerSourceTypePhotoLibrary ... everything works fine.
What in the heck am I missing or doing wrong? All I want to do is show the camera, take and save a picture.
FYI - I'm testing on my 3GS device.
Thanks to anyone who can help :)
This is very common. As long as you handle the memory warning without crashing and have enough space to keep going, don't let it drive you crazy.
It is not about how much memory your app has used, because it will probably happen even when you write a very simple app which have only one view with one button, clicking the button and then open camera.
I have tested on iPhone 3GS, iPad 2 and iPod touch 3G. It only happened in iPhone 3GS.
I found it will not happen anymore if you restart you device before you execute you app.
Another real solution is to comment the code, [super didReceiveMemoryWarning], in your viewController.
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
After lots of test on iPhone 3GS with iOS 4.3.2, I found the logic might like that:
-> Open as much as app running on background
-> Presenting a imagePicker of UIImagePickerController, clicking "Back" or "Save" from imagePicker
-> ApplicationDelegate's method, applicationDidReceiveMemoryWarning:(UIApplication *)application, will be invoked
-> Then ViewController's method, didReceiveMemoryWarning:, will be invoked
-> Then viewDidUnload
-> Then viewDidLoad
Then you could find some views have been released and the current view has been pointed to a unexpected one.
By default, [super didReceiveMemoryWarning] will run when ViewController's didReceiveMemoryWarning method is invoked. Commenting it, and viewDidUnload: and viewDidLoad: methods will not be invoked. It means the mem warning has been totally ignored. That's what we expected.
Now after I upgraded to 4.0 it happens to my app too - before in 3.1 there were no warnings.
Actually as you said before, there should be no issue. However, this causes the view that comes after it to load again and viewDidLoad is being called. This messes up my app, since I initialize the view in viewDidLoad - now it gets initialized all over again - even though it shouldn't.
Just as a comment, this might also happen to many other apps that rely on loading the view only once!
It did happen in my app Did I Do That on iOS 4.0 too. It was not consistent, but the most common cause was creating a UIImagePickerController instance and navigating to some large photo stored in one of the albums.
Fixed by persisting state in the didReceiveMemoryWarning method, and loading from state in the viewDidLoad method. One caveat is to remember to clear the state-persisted file in the correct point for your application. For me it was leaving the relevant UIViewController under normal circumstances.
I'm getting the memory warning when opening a UIImagePickerController as well. I'm on 4.01 as well.
But in addition, the UIImagePickerController is running the close shutter animation and stalling there, with the closed shutter on screen.
It seems like the UIImagePickerController's behavior on memory warnings is to close itself.
I could dismiss the UIImagePickerController from the parent ViewController in the didReceiveMemoryWarning method, but that would make for a terrible user experience.
Has anyone seen this problem?
Is there a way to handle the memory warning so that the UIImagePickerController doesn't shut itself down?
I have been struggling with the same problem for some days now. However, resetting my iPhone 4 (clearing out memory) solves the problem so it's not really an app problem.
It appears that a level 1 or 2 memory warning triggers the UIimgPickerController delegate to offload itself. The same happens in my app with the delegate of the delegate (yes it can). After the memory warning however, it will load the delegate (and it's delegate) again causing the viewDidLoad to execute any code that's in there.
I am not sure this happens only while using the UIimgPickerController because testing all that is very time consuming.
I could write some extra code to prevent the code in viewDidLoad en viewWillAppear from execuring while showing the UIimgPickerController but that's not classy, right?
Here's food for thought: it could be
that you are running out of memory
because you are testing your app. With
some memoryleaks it is very well
possible that you are working towards
this problem every time you debug.
The UIImagePickerControllerDelegate is a memory hog because you are capturing high memory assets, be that an image or video. So from the start be sure to specify the medium capture settings, as a start point, reduce this if you don't need the quality:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.videoQuality=UIImagePickerControllerQualityTypeMedium;
Then after capturing and using these assets. Remove any temp files from the applications temp folder. Could be an extra obsessive step but its a good habit:
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:[lastCapturedFile substringFromIndex:7] ]) {
NSError *error;
// Attempt to delete the folder containing globalDel.videoPath
if ([fileManager removeItemAtPath:[lastCapturedFile substringFromIndex:7] error:&error] != YES) {
NSLog(#"Unable to delete recorded file: %#", [error localizedDescription]);
} else {
NSLog(#"deleted file");
}
}
With above it is clearing the file that was created by the delegate. In some instances if you are transcoding or creating you own assets delete the folder with that file. Note above I am removing the 'file://' part of the url string as the file manager doesn't like it:
[lastCapturedFile substringFromIndex:7]
Other things to consider are covered in the various documentation for what you are doing with that asset - transcoding, image size reduction and more. Beware that any transcoding using the AVFoundation will crash if the UIImagePickerViewController is displaying.
I started to learn using Instrument, but I cannot figure it out.
After I start my application, the UI shows up, I do nothing and after few seconds I can see memory leak detected:
When I have a look at the second leak I can see the following stack:
When I double click on the cell related to my code I can see that it is pointing to the following line of code:
[window addSubview:newPostUIViewController.view];
from the method:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//creating view controller
newPostUIViewController = [[NewPostUIViewController alloc] initWithNibName:#"NewPostView" bundle:nil];
newPostUIViewController.title = #"Post it!";
[window addSubview:newPostUIViewController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
I wonder, how this can be a reason of a leak? I release newPostUIViewController in the dealloc method of PostItAppDelegate class.
Any ideas how this could be explained?
You did not provide an autorelease or release to balance your init. Just in case you haven't read through it already, have a look at the memory management guide is a great help.
Looking at link text allows to say that this is Simulator problem, not the code problem.
Maybe someone can help me with this strange thing:
If a user clicks on a button, a new UITableView is pushed to the navigation controller. This new view is doing some database querying which takes some time. Therefore I wanted to do the loading in background.
What works WITHOUT leaking memory (but freezes the screen until everything is done):
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self.workController loadList]; // Does the DB Query
[self.workController pushViewController:self.workController animated:YES];
Now I tried to do this:
// Show Wait indicator
....
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self performSelectorInBackground:#selector(getController) withObject:nil];
}
-(void) getController {
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
}
This also works but is leaking memory and I don't know why !
Can you help ?
By the way - is it possible for an App to get into AppStore with a small memory leak ? Or will this be checked first of all ?
Thanks in advance !
No, small memory leaks will not (most likely) you application to be rejected from appstore.
In your example as you run your method in separate thread you should create and dispose NSAutoreleasePool object for that thread to handle autoreleased objects. Following changes to getController method should do the trick:
-(void) getController {
NSAutoreleasedPool *pool = [[NSAutoreleasedPool alloc] init];
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
[pool release];
}
For more details see Autorelease Pools section in memory management guide. Relevant quote from there:
If you spawn a secondary thread, you
must create your own autorelease pool
as soon as the thread begins
executing; otherwise, you will leak
objects. (See “Autorelease Pools and
Threads” for details.)
Btw, you're calling pushViewController: from a background thread. This is bad.
You should only do things to the UI - like pushing view controllers and changing UI items - from the main thread. If you don't, things break.
See the Cocoa Fundamentals Guide section titled "Are the Cocoa Frameworks Thread Safe?": it says "All UIKit objects should be used on the main thread only."