UIGraphicsGetImageFromCurrentImageContext () – Fuite de memory

UIImagePickerControllerSourceTypeCamera la camera avec UIImagePickerControllerSourceTypeCamera et un cameraOverlayView personnalisé afin que je puisse prendre plusieurs photos sans l'étape "Use Photo".

Cela fonctionne très bien, mais il y a une fuite de memory dans la fonction de sauvegarde de photos. Grâce à beaucoup de debugging et de search, je l'ai réduit à la fonction UIGraphicsGetImageFromCurrentImageContext .

Voici un extrait de code où cela arrive:

 UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]); [[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()]; UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

J'ai parcouru internet et il semble que la fonction UIGraphicsGetImageFromCurrentImageContext() (citée à partir de cette question SO ) "renvoie une nouvelle UIImage UIImage et pointe vers lui la dernière version de UIImage précédemment allouée n'est jamais réellement libérée, la variable est juste rejointé ailleurs. "

J'ai essayé tellement de solutions qui ont apparemment fonctionné pour d'autres:

  • Ajout de timestampedImage.layer.contents = nil; après UIGraphicsEndImageContext

  • Ajout de CGContextRef context = UIGraphicsGetCurrentContext(); et CGContextRelease(context); après UIGraphicsEndImageContext

  • Envelopper l'extrait ci-dessus dans un NSAutoreleasePool

  • Envelopper la fonction entière saveThisPhoto dans un NSAutoreleasePool

  • Création d'un NSAutoreleasePool lorsque la camera s'ouvre et appelle [pool release] quand didReceiveMemoryWarning est appelé

  • Fermeture de la window contextuelle de la camera lors de l' didReceiveMemoryWarning , en espérant qu'elle didReceiveMemoryWarning le pool

  • Chaque combinaison possible de ce qui précède

Pourtant, tout ce que j'essaie, quand je prends des photos, je peux voir la Memory Utilized s'élever et ne pas tomber quand je prends à plusieurs resockets des photos sur l'appareil.

Est-ce que quelqu'un sait comment je peux libérer l'object autorelease créé par UIGraphicsGetImageFromCurrentImageContext ?

Alternativement, existe-t-il une autre façon de faire un UIImage sur un UIImageView ?

Modifier:

Voici les fonctions complètes comme demandé. Il y a beaucoup d'autres versions ajoutées juste pour essayer de s'assurer que tout est nettoyé. J'ai testé et testé systématiquement la fuite de memory avec chaque bloc de code dans saveThisPhoto , et cela ne se produit que lorsque le bloc UIGraphicsGetImageFromCurrentImageContext (extrait ci-dessus) est exécuté.

 - (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:[NSSsortingng ssortingngWithFormat:@"%d", photoCount] forKey:@"photocount"]; [[NSUserDefaults standardUserDefaults] synchronize]; // Obtaining saving path NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSSsortingng *documentsDirectory = [paths objectAtIndex:0]; NSSsortingng *fileName = [NSSsortingng ssortingngWithFormat:@"ri_%d.jpg", photoCount]; NSSsortingng *fileNameThumb = [NSSsortingng ssortingngWithFormat:@"ri_%d_thumb.jpg", photoCount]; NSSsortingng *imagePath = [documentsDirectory ssortingngByAppendingPathComponent:fileName]; NSSsortingng *imagePathThumb = [documentsDirectory ssortingngByAppendingPathComponent:fileNameThumb]; // Extracting image from the picker and saving it NSSsortingng *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; // SAVE TO IPAD AND DB if ([mediaType isEqualToSsortingng:@"public.image"]){ // Get Image UIImage *editedImage = [info objectForKey:UIImagePickerControllerOriginalImage]; // Figure out image orientation CGSize resizedSize; CGSize thumbSize; if (editedImage.size.height > 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(@">>> IMAGE ***NOT*** SAVED"); } NSLog(@"IMAGE SAVED - COMPLETE"); info = nil; [info release]; } 

Vous définissez vos variables sur zéro avant de les relâcher, et certaines sont déjà libérées automatiquement.

Normalement, lors de l'utilisation de la version, vous devez les relâcher et les mettre à zéro.

 [var release] var = nil; 

Mais dans certains d'entre eux, vous ne devriez pas appeler la libération.

Le suivant est votre principal coupable.

  // clean up the one we won't use any more timestampedImage = nil; [timestampedImage release]; // SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER