views:

97

answers:

2

Hi everyone!

In my game I'm grabbing an image from the iPhone's photo library using the UIImagePickerController, which returns a UIImage. Because the image is a huge resolution (1536x2048), this UIImage takes up almost 20mb in memory. To resolve this, I shrink the image significantly before using it to generate a sprite and this works in reducing the memory footprint. However, there is a brief moment before the image is resized that my memory usage spikes really high, and I'm worried this could cause crashes in low memory situations (although I don't get any low memory warnings). Anyone have any ideas on how to deal with this scenario?

Thanks!

A: 

I can confirm exactly what you're saying: UIImagePicker is, for a fairly brief moment of its lifetime, a massive RAM hog.

All I can tell you is to clear as much memory as you can on your way in. I managed to minimize crashing by ditching every other image I have in memory and loading it back in after I catch and resize the UIImage I'm returned from the Picker.

The only REAL solution I found was to get myself an iPhone 4. It has enough memory to cope. My poor old 3G was very easy to crush with UIImagePicker.

Dan Ray
get an iphone 4. nice :D i might need to get me one of those.
Pavan
Do you know if this is somehow the fault of the UIImagePicker itself or if it's directly due to the size of the image?
stefan_g
@stefan_g, It's a function of the image that UIImagePicker is loading, but there's no stopping it from loading a gigantic image if it wants to. Pulling images in from the camera is a bulky endeavor as well... Best policy is just to get out of its way as much as possible.
Dan Ray
+1  A: 

Have a look at this it talks about resizing images and so on correctly:

http://stackoverflow.com/questions/1282830/uiimagepickercontroller-uiimage-memory-and-more

Its a great tutorial on FAQ on uiimagepickercontroller, uiimage, memory and more.

EDIT:

Memory warnings are extremely common when dealing with the UIImagePickerController. This is especially true when using the camera. Keep in mind that while a JPG or PNG on disk may only amount to a few MB, the uncompressed in memory bitmap used to draw the image uses considerably more.

There's nothing that you're doing wrong necessarily, but some improvements can be made:

Rather than storing the image bytes in Core Data, why not write the image to disk and store the path to the file in your database?

and if you are using autorelease, rather than using so many autoreleased images, can you find a way to manage their lifecycle directly and release them sooner?

Your best bet may be to write the images to disk as soon after processing as possible and free up the memory they're using. Then store their location using Core Data rather than the raw data.

Or even remove all images loaded, store to disk, load new image, then store to disk, then load images via the path. something like that.

you can some modified code like so: http://stackoverflow.com/questions/3041781/getting-crash-after-picking-images-from-uiimagepickercontroller-related-to-memor

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{

    [self dismissModalViewControllerAnimated:YES];

    if (object.imagePath != nil) {
        [self deleteImages];
    }
    dispatch_queue_t image_queue;
    image_queue = dispatch_queue_create("com.gordonfontenot.app", NULL);

    dispatch_async(image_queue, ^{

        NSDate *now = [NSDate date];

        NSDateFormatter *f = [[NSDateFormatter alloc] init];
        [f setDateFormat:@"yyyyMMDDHHmmss"];

        NSString *imageName = [NSString stringWithFormat:@"Image-%@-%i", [f stringFromDate:now], arc4random() % 100];
        NSString *thumbName = [NSString stringWithFormat:@"%@-thumb", imageName];

        [f release];

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];

        NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:imageName];
        NSString *thumbPath = [documentsDirectory stringByAppendingPathComponent:thumbName];

        NSData *thumbImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerEditedImage"] toSize:CGSizeMake(120, 120)]);
        [thumbImageData writeToFile:thumbPath atomically:NO];
        dispatch_async(dispatch_get_main_queue(), ^{
            object.thumbPath = thumbPath;
            [self setupImageButton];
            imageButton.enabled = NO;
            [self setupChooseImageButton];
        });
        NSData *fullImageData = UIImagePNGRepresentation([UIImageManipulator scaleImage:[info objectForKey:@"UIImagePickerControllerOriginalImage"] toSize:CGSizeMake(800, 600)]);
        [fullImageData writeToFile:fullPath atomically:NO];

        dispatch_async(dispatch_get_main_queue(), ^{
            imageButton.enabled = YES;
            object.imagePath = fullPath;
        });

        if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            UIImageWriteToSavedPhotosAlbum([info objectForKey:@"UIImagePickerControllerOriginalImage"], self, nil, nil);
        }

    });
    dispatch_release(image_queue);
}

Hopefully you have enough information to go on from here.

PK

Pavan
Yeah this is the exact tutorial I grabbed my resizing code from. It doesn't mention what to do about the memory spike though :(
stefan_g
@Pavan - It's a good tutorial, but there's still a moment when the image that comes back is gobsmackingly massive and there's just nothing to do about that but move the breakable dishes off the table.
Dan Ray
ok ive updated the post after doing som research and taking a few options from different questions and found something you can do for now since you cant do anything else directly as the way you want it to work.
Pavan