Note that there are some explanatory texts on larger screens.

plurals
  1. POUIGraphicsGetImageFromCurrentImageContext() - Memory Leak
    primarykey
    data
    text
    <p>I am opening the camera with <code>UIImagePickerControllerSourceTypeCamera</code> and a custom <code>cameraOverlayView</code> so I can take multiple photos without the "Use Photo" step.</p> <p>This is working great, but there is a memory leak in the save photo function. Through a lot of debugging and research I have narrowed it down to the <code>UIGraphicsGetImageFromCurrentImageContext</code> function.</p> <p>Here is a snippet of code where it happens:</p> <pre><code>UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]); [[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); </code></pre> <p>I have scoured the internet and it seems that the <code>UIGraphicsGetImageFromCurrentImageContext()</code> function (quoted from <a href="https://stackoverflow.com/questions/4498874/how-i-solve-memory-leak-problem">this SO question</a>) <em>"returns a new autoreleased <code>UIImage</code> and points the <code>finalTimestampImage</code> ivar to it. The previously allocated <code>UIImage</code> is never actually released, the variable to it is just repointed to somewhere else."</em> </p> <p>I've tried so many solutions that have apparently worked for others:</p> <ul> <li><p>Adding <code>timestampedImage.layer.contents = nil;</code> after <code>UIGraphicsEndImageContext</code></p></li> <li><p>Adding <code>CGContextRef context = UIGraphicsGetCurrentContext();</code> and <code>CGContextRelease(context);</code> after <code>UIGraphicsEndImageContext</code></p></li> <li><p>Wrapping the above snippet in an <code>NSAutoreleasePool</code></p></li> <li><p>Wrapping the entire <code>saveThisPhoto</code> function in an <code>NSAutoreleasePool</code></p></li> <li><p>Creating an <code>NSAutoreleasePool</code> when the camera pops up and calling the <code>[pool release]</code> when <code>didReceiveMemoryWarning</code> is called</p></li> <li><p>Closing the camera popup when <code>didReceiveMemoryWarning</code> is called, hoping it will clear the pool</p></li> <li><p>Every possibly combination of the above</p></li> </ul> <p>Yet everything I try, when I take photos I can see the <code>Memory Utilized</code> rising and not falling when I'm repeatedly taking photos on the device.</p> <p>Does anyone know how I can release the autorelease object created by <code>UIGraphicsGetImageFromCurrentImageContext</code>?</p> <p>Alternatively, is there an alternative way to make a <code>UIImage</code> out of an <code>UIImageView</code>?</p> <p><strong>Edit:</strong> </p> <p>Here are the full functions as requested. There's a lot of extra releasing added in there just to try make sure <em>everything</em> is cleaned up. I have gone through and tested for the memory leak with each code block in <code>saveThisPhoto</code> systematically, and it only occurs when the <code>UIGraphicsGetImageFromCurrentImageContext</code> block (snippet above) is run.</p> <pre><code>- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSLog(@"SAVING PHOTO"); [self saveThisPhoto:info]; picker = nil; [picker release]; info = nil; [info release]; } - (void)saveThisPhoto:(NSDictionary *)info { // Get photo count for filename so we're not overriding photos int photoCount = 0; if ([[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"]) { photoCount= [[[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"] intValue]; photoCount++; } [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%d", photoCount] forKey:@"photocount"]; [[NSUserDefaults standardUserDefaults] synchronize]; // Obtaining saving path NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *fileName = [NSString stringWithFormat:@"ri_%d.jpg", photoCount]; NSString *fileNameThumb = [NSString stringWithFormat:@"ri_%d_thumb.jpg", photoCount]; NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:fileName]; NSString *imagePathThumb = [documentsDirectory stringByAppendingPathComponent:fileNameThumb]; // Extracting image from the picker and saving it NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; // SAVE TO IPAD AND DB if ([mediaType isEqualToString:@"public.image"]){ // Get Image UIImage *editedImage = [info objectForKey:UIImagePickerControllerOriginalImage]; // Figure out image orientation CGSize resizedSize; CGSize thumbSize; if (editedImage.size.height &gt; editedImage.size.width) { resizedSize = CGSizeMake(480, 640); thumbSize = CGSizeMake(150, 200); } else { resizedSize = CGSizeMake(640, 480); thumbSize = CGSizeMake(150, 113); } // MAKE NORMAL SIZE IMAGE UIImage *editedImageResized = [editedImage resizedImage:resizedSize interpolationQuality:0.8]; // clean up the one we won't use any more editedImage = nil; [editedImage release]; // ADD TIMESTAMP TO IMAGE // make the view UIImageView *timestampedImage = [[UIImageView alloc] initWithImage:editedImageResized]; CGRect thisRect = CGRectMake(editedImageResized.size.width - 510, editedImageResized.size.height - 30, 500, 20); // clean up editedImageResized = nil; [editedImageResized release]; // make the label UILabel *timeLabel = [[UILabel alloc] initWithFrame:thisRect]; timeLabel.textAlignment = UITextAlignmentRight; timeLabel.textColor = [UIColor yellowColor]; timeLabel.backgroundColor = [UIColor clearColor]; timeLabel.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:(25.0)]; timeLabel.text = [self getTodaysDateDatabaseFormat]; [timestampedImage addSubview:timeLabel]; // clean up what we won't use any more timeLabel = nil; [timeLabel release]; // make UIIMage out of the imageview -- MEMORY LEAK LOOKS LIKE IT IS IN THIS BLOCK NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]); [[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); timestampedImage.layer.contents = nil; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRelease(context); // clean up the one we won't use any more timestampedImage = nil; [timestampedImage release]; // SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER NSData *webDataResized = UIImageJPEGRepresentation(finalTimestampImage, 1.0); // JPG [webDataResized writeToFile:imagePath atomically:YES]; // clean up the one we won't use any more finalTimestampImage = nil; [finalTimestampImage release]; [pool release]; // to get rid of the context image that is stored // SAVE TO DATABASE [sqlite executeNonQuery:@"INSERT INTO inspection_images (agentid,groupid,inspectionid,areaid,filename,filenamethumb,filepath,orderid,type) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?) ", [NSNumber numberWithInt:loggedIn], [NSNumber numberWithInt:loggedInGroup], myInspectionID, [[tableData objectAtIndex:alertDoMe] objectForKey:@"areaid"], fileName, fileNameThumb, documentsDirectory, [NSNumber numberWithInt:photoCount], [NSNumber numberWithInt:isPCR] ]; // Clean up webDataResized = nil; [webDataResized release]; } else { NSLog(@"&gt;&gt;&gt; IMAGE ***NOT*** SAVED"); } NSLog(@"IMAGE SAVED - COMPLETE"); info = nil; [info release]; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload