Yannick Winter
Yannick Winter

Reputation: 103

iOS App crashes when taking a photo

my App crashes when taking a photo due to a memory issue.

Now I tried to analyze my memory with instruments and actually I am using a maximum of 23 MB when the app crashes. I compared it with that Facebook App and it uses more than 70 MB so I do not have an idea why I am getting memory warnings...

I use the following code:

OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.cameraOverlayView = overlay;
[self presentViewController:picker animated:NO completion:nil];

Note: I have tried it without the overlay view and it did not seem to change and I tried it with and without animation.

BTW the app does not crash when presenting the imagepicker, but when the imagepicker is shown I receive multiple memory warnings. The App crashes either when taking the photo or when hitting the 'use' button. Sometimes the App does not crash at all so I am very confused.

Maybe I need to do something in the didReceiveMemoryWarning method but I do not know what, maybe you can help me out with that!

Xcode shows this:

memory issue

Update:

This is what i get from the

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImagePickerControllerMediaMetadata =     {
    DPIHeight = 72;
    DPIWidth = 72;
    Orientation = 6;
    "{Exif}" =         {
        ApertureValue = "2.526068811667588";
        BrightnessValue = "3.440519128732857";
        ColorSpace = 1;
        DateTimeDigitized = "2013:09:26 14:33:48";
        DateTimeOriginal = "2013:09:26 14:33:48";
        ExposureMode = 0;
        ExposureProgram = 2;
        ExposureTime = "0.03333333333333333";
        FNumber = "2.4";
        Flash = 24;
        FocalLenIn35mmFilm = 35;
        FocalLength = "4.28";
        ISOSpeedRatings =             (
            50
        );
        LensMake = Apple;
        LensModel = "iPhone 4S back camera 4.28mm f/2.4";
        LensSpecification =             (
            "4.28",
            "4.28",
            "2.4",
            "2.4"
        );
        MeteringMode = 5;
        PixelXDimension = 3264;
        PixelYDimension = 2448;
        SceneType = 1;
        SensingMethod = 2;
        ShutterSpeedValue = "4.906905022631062";
        SubjectArea =             (
            1631,
            1223,
            881,
            881
        );
        SubsecTimeDigitized = 551;
        SubsecTimeOriginal = 551;
        WhiteBalance = 0;
    };
    "{MakerApple}" =         {
        1 = 0;
        3 =             {
            epoch = 0;
            flags = 1;
            timescale = 1000000000;
            value = 779858689639583;
        };
        4 = 0;
        5 = 128;
        6 = 138;
        7 = 0;
    };
    "{TIFF}" =         {
        DateTime = "2013:09:26 14:33:48";
        Make = Apple;
        Model = "iPhone 4S";
        Software = "7.0";
        XResolution = 72;
        YResolution = 72;
    };
};
UIImagePickerControllerMediaType = "public.image";
UIImagePickerControllerOriginalImage = "<UIImage: 0x15668c60>";

}

Upvotes: 3

Views: 6036

Answers (2)

navroz
navroz

Reputation: 402

Iam also facing the same problem and i have found an patch to minimize the issue .So What i does is simply block the main thread untill image picker is dismissed. that's it .

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
__weak typeof(picker) wSelf = picker;
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 *NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[wSelf dismissViewControllerAnimated:YES completion:^{
    @try {


        [self saveImage:info];
    }
    @catch (NSException *exception) {
        NSLog(@"Exception:%@",exception);
    }
    @finally {
    }

}];});}

-(void)saveImage:(NSDictionary *)info{
 [KAppdelegate ShowLoader];

  UIImage *image=(UIImage *)[info objectForKey:@"UIImagePickerControllerOriginalImage"];

  ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
 dispatch_queue_t queue =  dispatch_queue_create("com.myApp.saveToCameraRoll", NULL);
dispatch_async(queue, ^{
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[library writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){

    if (error) {
        // handle the error
    }
    else {
        dispatch_async(dispatch_get_main_queue(), ^{
            // perhaps indicate to the user that save has finished

        });
    }

    dispatch_semaphore_signal(sema);

}];

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

});}

Upvotes: 0

JRG-Developer
JRG-Developer

Reputation: 12663

Don't worry about the memory warning. If you're using UIImagePickerController on iPhone 4S or older devices, you'll typically get this warning, and you can't do much about it.

What's important is that you need to make sure you're resizing the image appropriately via your delegate method for imagePickerController:didFinishPickingMediaWithInfo:. If you try to save and use (such as displaying in UIImageView) the original image, you will crash on these older devices due to memory pressure.

See this excellent blog post for a discussion on the correct way to resize a UIImage.

Specifically, you will find this category to be helpful for resizing images correctly:

UIImage+Resize.h

UIImage+Resize.m

If you already use another method that works, great. Otherwise, this method works very well.

Using said category methods, here's an example of imagePickerController:didFinishPickingMediaWithInfo: using GCD to do the resizing on a background thread:

- (void)imagePickerController:(UIImagePickerController *)imagePicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    // Dismiss the image picker first to free its memory
    [self dismissViewControllerAnimated:YES completion:nil];

    UIImage *originalImage = info[UIImagePickerControllerOriginalImage];

    if (!originalImage)
        return;

    // Optionally set a placeholder image here while resizing happens in background

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Set desired maximum height and calculate width
        CGFloat height = 640.0f;
        CGFloat width = (height / self.size.height) * self.size.width;

        UIImage * image = [originalImage resizedImage:CGSizeMake(width, height) interpolationQuality:kCGInterpolationDefault];

        // Save and use this image
    });
}

Upvotes: 3

Related Questions