Using Instruments to trace memory leak Xcode5 and iOS7 - ios

I developed my first app and still learning. Just updated Xcode 5 yesterday and my iPhone 5 is running iOS 7.1. I am now working on understanding the Instruments tool to analyze my app. I am using the Leak profile in Instruments and have come across a retain cycle and leak which I can't figure out. Appreciate any help I can get to understand a) how to pinpoint the bug and b) what I did wrong and how to avoid it in the future.
In my app, I am using the camera to take a pic. While the camera is up, I tapped on the screen to focus and that is when I noticed the leak pop up in Instruments. Looks like there is a retain cycle not in my code (if I understand correctly) and a root leak in my code which I don't understand.
I am using ARC, so I should not have to release "picker" in the part of my code that Instruments is pointing me to (part 2 below, with code).
What can I do about the retain cycle. It is not in my code, but am I still the cause of it? Does it stem from the "root leak?" If I am NOT responsible for it, what's should I do about it?
My only code in this stack trace does not help me understand where the leak is coming from. The line is Instruments points me to in my code is [picker dismissViewControllerAnimated:YES completion:nil]; in my imagePickerController:didFinishPickingMediaWithInfo: method. I am pasting the code below.
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *pickerImage = [info objectForKey:
UIImagePickerControllerOriginalImage];
_imageView.image = pickerImage;
[picker dismissViewControllerAnimated:YES completion:nil]; // <--- mem-leak
}
EDIT - Code where I create my UIImagePickerController.
- (IBAction)snapPicture:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// If the camera button was tapped AND we have a camera, use it...
if ((sender == _cameraButton) && [UIImagePickerController
isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}
imagePicker.delegate = self;
// bring up the image picker view
[self presentViewController:imagePicker animated:YES completion:nil];
}

Here's my theory: what you've encountered is evidently a bug (or flaw) in Apple's own code, and all you can do is laugh maniacally and forget about it.
To test my theory, I ran my own code, written totally separately and at a different time. It does almost the same thing your code does: it lets the user take a picture, and puts the image into the interface. Here's my code:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch17p702takeAPicture/ch30p962takeAPicture/ViewController.m
I ran my code under Instruments with the Leaks instrument, and guess what? I saw the same issues you did.
Naturally, I then started searching on Stack Overflow, and all of this turns out to be old ground. For example:
UIImagePickerController memory leak on iOS5
Even Apple's own sample code, called PhotoPicker (or Using UIImagePickerController to Select Pictures and Take Photos) has the same leak.

Related

Collection <__NSArrayM: 0x170e45d00> was mutated while being enumerated - UIImagePickerConteroller didFinishPickingMediaWithInfo

I have a native Objective-C application that takes photo using UIImagePickerConteroller. Once UIImagePickerController didFinishPickingMedia delegate function return image, I am storing the image in my app document directory and storing the the image location in an array so that I can show it in my application gallery view.
NOT frequently, but once or twice in a month I am receiving a crash log in AppSee/Fabric crash tracker, after user finished taking photo.
In Appsee video I can see where exactly the crash happened. Crash log says NSArray was mutated while being enumerated(Check the attached image). Now I am NOT doing any addObject or removeObject functionality to my photo mutableArray at the time of enumeration. I am doing a mutable copy of my photo array before reading data to show it my photo gallery. So no chance of mutation while being enumerated.
According to the crash log, it seems like the issue is related to UIImagePickerController. Because the log said -
-[CAMPriorityNotificationCenter _postNotification:forEntries:]
-[CAMPriorityNotificationCenter _notificationReceiver:]
And 'CAMPriorityNotification' is used by UIImagePickerController class. But not sure if UIImagePickerController is throwing an error and causing crash. I putted #try #catch in didFinishPickingMedia function to find the crash issue. But #try #catch is not throwing an error. So that is making more confusion to me.
Is there anyone faced similar type of crash issue after taking photo? Any suggestion i would appreciate.
This is an apple issue. Apple responded to my bug report. Here is the response from them -
"Engineering has determined that your bug report (31369562) is a duplicate of another issue (29753773) and will be closed.
The open or closed status of the original bug report your issue was duplicated to appears in the yellow "Duplicate of XXXXXXXX" section of the bug reporter user interface. This section appears near the top of the right column's bug detail view just under the bug number, title, state, product and rank."
Try to set your reference to UIImagePickerController* to nil in 2 cases:
when you have received image from controller - in function
"didFinishPickingImage"
when you go to background or go back from screen that have link to UIImagePickerController via property. I did it in call viewDidDissapear:
- (void)viewDidDissapear:(BOOL)animated {
[super viewDidDissapear: animated];
self.photoPicker = nil; // that property of type UIImagePickerController*
}



I had a lot of crashes in CAMPriorityNotificationCenter, all in background. After these 2 changes (mentioned above) - crashes didn't appear.
So I was getting this iOS 14 and 15 regularly until I changed my code to not do anything in the completion handler. I used to do my image saving/processing in there.
This is how it was written:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
[picker dismissViewControlle Animated:YES
completion:^{
// Process and Save Image
}];
}
And now I have changed it to:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
if (picker.isBeingDismissed) {
return;
}
[picker dismissViewControllerAnimated:YES
completion:nil];
// Process and save image
}
I was getting this crash a couple of times a week and now its been about 2 weeks without a crash.
Update - so I'm still getting these about once a fortnight now. All on 14.* devices...
It looks like your code may access an collection and modify it at the same time.

iOS: idleTimerDisabled = YES works only until ImagePicker was used

I have an iPad survey tool as an internal enterprise application. I prevent screen locking with setting [[UIApplication sharedApplication] setIdleTimerDisabled: YES]; at didFinishLaunchingWithOptions of the application delegate.
That works fine until I use the imagePicker to take an image. After that, the idleTimer is activated again. I have tried to disable it after the image was taken but that doesn't work.
Here I found the hint that setting the required device capabilities in the info.plist could help. But so far it didn't. I have just added all camera specific flags.
Any ideas?
Many thanks!
Marcus
I was able to reset the UIApplication idleTimerDisabled like so:
- (void)resetIdleTimerDisabled
{
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self dismissViewControllerAnimated:YES completion:^{
[self performSelector:#selector(resetIdleTimerDisabled) withObject:nil afterDelay:1.0];
}];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:^{
[self performSelector:#selector(resetIdleTimerDisabled) withObject:nil afterDelay:1.0];
}];
}
What I suspect is happening is that internally UIImagePickerController sets UIApplication.idleTimerDisabled to YES to keep the camera from sleeping. When finished (after the delegate methods are called and apparently even after the animation completion block is executed), the UIImagePickerController sets UIApplication.idleTimerDisabled back to NO. Instead, it only should do this if the value was previously NO.
I filed a bug report with Apple. See UIImageViewControllerBug sample project.
Jamie's solution looks good! I'm just not a big fan of afterDelay: methods:)
The issue is in the PhotoLibrary framework: it disables the idleTimer prior to starting preview stream from camera and enables it again when tearing it down regardless of the previous value.
If you feel more adventures and want solution that works throughout the app, here is one involving swizzling: https://gist.github.com/zats/1a4aece697075478b44a
Tested for both cases when idleTimer disabled or enabled prior to showing image picker. My solution does not observe idleTimerDisabled while image picker is presented.
P.S. the same issue happens when using dictation feature (bug in UIDictationController)
(#jamie-mcdaniel if you would be so kind to update your bug report)

Laggy presentation of SLServiceTypeFacebook

so I'm making a post to Facebook and want the user to select an image before doing that.
Once the image is picked and I show Facebook. Problem is, when I show Facebook straight away, without the image picking part, it looks fine. When I show it after picking the image, Facebook sharing appears animated, but laggy. As if the action has a very low framerate or something.
Here's my code:
self.portraitPicker = [[UIImagePickerController alloc] init];
#if !(TARGET_IPHONE_SIMULATOR)
self.portraitPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
#endif
[self.portraitPicker setDelegate:self];
self.portraitPicker.allowsEditing = YES;
[self presentViewController:self.portraitPicker animated:YES completion:nil];
Now when this is complete, I show the Facebook posting modally:
[picker dismissViewControllerAnimated:YES completion:^{
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook])
{
self.facebookController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[self.facebookController setInitialText:#"Some text"];
[facebookController addImage:pickedImage];
[self presentViewController:self.facebookController animated:NO completion:nil];
}
}];
I can do this in the didFinishPickingMediaWithInfo or the imagePickerControllerDidCancel, doesn't matter, the problem still comes up.
Being desperate, I tried:
Showing it on the main thread delayed
Showing it async
Showing it outside the dismiss-block
Showing it from the AppDelegate's rootviewcontroller instead
This is not Facebook-related as it happens with SLServiceTypeTwitter as well as with MFMessageComposeViewController.
Can't seem to do away with the laggy animation that ONLY happens showing the image picker. Does anyone know what's causing this?
Given the lack of response and similar issues, I figured the cause was my own architecture.
It turns out that one of my viewcontrollers' ViewDidAppear was called after the camera picker was displayed (as it became the active viewcontroller and consequently the inactive one, giving control back to the original viewcontroller).
Blocking the background calls and animation that happened in this viewDidAppear resolved the issue. I still don't know why calling it delayed (i.e. 10 seconds, or even 100 seconds into the future, when nothing was going on) still had the laggy appearence show up, but there it is.

Presenting UIImagePickerController in camera mode causes crash in iOS 7

At the time of presenting UIImagePickerController in camera mode using the code below, Xcode 5 memory view shows that my app consumes about 20 MB. When I present the controller, I receive memory warning in the overrode didReceiveMemoryWarning. But even without a chance to release any resources in there, the app just crashes without leaving any log messages. I am running the code in an iPhone 4S. I see other similar questions but the symptoms are slightly different than mine and I don't see any clear answers that led to resolving my issue. The same code does not cause a problem in iOS 6 or when I present the controller in photo library mode. My specific questions are:
Would it be normal to get memory warning with about 20 MB memory usage when presenting UIImagePickerController in camera mode?
Should I deal with this problem by reducing the memory consumption level further before I present the UIImagePickerController?
===
- (IBAction)cameraClicked:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.navigationBarHidden = YES;
imagePicker.toolbarHidden = YES;
imagePicker.allowsEditing = NO;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:imagePicker animated:YES completion:nil];
}
What is the error you are getting is it ? EXC_BAD_ACCESS
Try to debug with NSZombieEnabled available in instruments and also Symbolic and exceptional breakpoints so that you can trace the reason for the crash.

UIImagePickerController appears but camera doesn't start on iOS 5

I have an app where I present a UIImagePickerController with source type UIImagePickerControllerSourceTypeCamera. Everything works fine unless I leave the app and come back (multitasking is enabled so the app comes back right where it left off) and I present the UIImagePickerController again. It appears on screen but the camera never shows, the animation where the camera is revealed never happens, here is a screenshot:
If I press cancel and present the UIImagePickerController again, the camera will show up fine. So the only time this problem occurs is the first time I present the UIImagePickerController after coming back to the app. Anyone know why this is happening? I'm coding for iOS 5
I'm presenting the UIImagePickerController with:
[self presentViewController:capturePhotoPicker animated:YES completion:nil];
and dismissing it with:
[self dismissViewControllerAnimated:YES completion:nil];
I am using the same UIImagePickerController object each time I present it
I had exactly the same problem and then realized I wasn't releasing the UIImagePickerController after presenting it. The camera now works fine first-time after leaving and returning to the app.
So this is my exact code:
UIImagePickerController *takePhotoController = [[UIImagePickerController alloc] init];
takePhotoController.sourceType = UIImagePickerControllerSourceTypeCamera;
takePhotoController.delegate = self;
[self presentModalViewController:takePhotoController animated:YES];
[takePhotoController release];
It's one of those problems you can spend ages on, and the solution is not that obvious (well, it wasn't to me), so I hope this helps some people!
if you change the -(void)viewDidLoad to - (void)viewDidAppear:(BOOL)animated it fixes the problem. I've spent the last 2 weeks trying to figure this out

Resources