Sunday, May 1, 2011

iPhone Memory Management with UIImage

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:

(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self.pickerTrigger setImage:image];
[self.button setTitle:@" " forState:UIControlStateNormal];
[self.button setTitle:@" " forState:UIControlStateSelected];
[self.button setTitle:@" " forState:UIControlStateHighlighted];

CGSize oldSize = [image size];
CGFloat width = oldSize.width;
CGFloat height = oldSize.height;
CGSize targetSize = CGSizeMake(320.0, 400.0);
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

if (CGSizeEqualToSize(oldSize, targetSize) == NO)
{
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;

if (widthFactor > heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;

if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else
if (widthFactor < heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}

UIGraphicsBeginImageContext(targetSize);

CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[image drawInRect:thumbnailRect];

>     self.selectedImage = UIGraphicsGetImageFromCurrentImageContext();

    NSLog([NSString stringWithFormat:@"After getting from DB %d", [selectedImage retainCount]]);
    UIGraphicsEndImageContext();
    [pool release];
    [picker dismissModalViewControllerAnimated:YES];

}

the variable selectedImage has been declared as a retained property in the interface file. As you can guess I thumbnail an image to store it in selectedImage. then I reuse it in another funtion and release it in the dealloc funtion.

Instruments shows that the object does get deallocated but memory keeps increasing? Does it mean that releasing objects doesn't necessarily free the memory?

I face this kinda thing too often with UIImages? Any guesses?

I have added [selectedImage release] to the (void)dealloc function which does get called , retain count becomes zero and the object does get deallocated. But some memory is allocated (I believe while using UIGraphicsGetImageFromCurrentImageContext(); I guess) which is not freed. I add 4-5 Images the memory reaches a whopping 117 MB in the simulator then it drops back to 48 MB in the simulator. But the app crashes on the iPhone. Should I take some other approach while creating the image??

From stackoverflow
  • If you have selectedImage declared as a "retained property" then you have to send it a message to release it.

    This is because the image is retained inside the implicit call for the setter: self.selectedImage = XXX. You cannot see it, because its in the code the compiler creates for the property setter.

  • Instruments shows that the object does get deallocated but memory keeps increasing? Does it mean that releasing objects doesn't necessarily free the memory?

    When you release an object it reduces it ref counter by 1, it is only released form memory when that counter hits zero.

    Your UIImage will not be released if something else is using it, this might be your code or a view you created in Interface builder.

    It is possible you are calling retain too main times thus the ref counter will never reach zero.

    Also, remember that at the start of every event cycle on the iPhone an Auto Release pool is created, you can alway add your object to that and have them cleaned up automatically.

0 comments:

Post a Comment