1

I'd like to save UIImage in NSArray to local as PNG. However, When I used UIImagePNGRepresentation in a for-loop, memory grew up greatly even though there is already a @autoreleasepool.

for (int i = 0; i < array.count; i++) {

    @autoreleasepool {
        NSDictionary *src = array[i];

        NSString *localPath = [SPLDPath stringByAppendingPathComponent:@"realImg"];
        NSFileManager *file = [NSFileManager defaultManager];
        if (![file fileExistsAtPath:localPath]) {
            [file createDirectoryAtPath:localPath withIntermediateDirectories:NO attributes:nil error:nil];
        }

        NSString *screenShotImg = [localPath stringByAppendingPathComponent:[NSString stringWithFormat:@"ScreenShot_%d.png", i]];
        NSData *PNGData = UIImagePNGRepresentation(src[@"image"]);
        [PNGData writeToFile:screenShotImg atomically:YES];
    }
}

So I tried to convert UIImage to CGImageRef and use ImageIO framework to save image. Then using CGImageRelease() to release memory in each loop.

-(void)saveImage:(CGImageRef)image directory:(NSString*)directory filename:(NSString*)filename  {
@autoreleasepool {
    CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", directory, filename]];
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
    CGImageDestinationAddImage(destination, image, nil);

    if (!CGImageDestinationFinalize(destination))
        NSLog(@"ERROR saving: %@", url);

    CFRelease(destination);
    CGImageRelease(image);
}

}

for (int i = 0; i < array.count; i++) {

   NSDictionary *src = array[i];

   NSString *localPath = [SPLDPath stringByAppendingPathComponent:@"realImg"];
        NSFileManager *file = [NSFileManager defaultManager];
   if (![file fileExistsAtPath:localPath]) {
       [file createDirectoryAtPath:localPath withIntermediateDirectories:NO attributes:nil error:nil];
   }
   NSString *fileName = [NSString stringWithFormat: @"ScreenShot_%d.png", i];

   CGImageRef cgRef=[src[@"image"] CGImage];
   [self saveImage:(cgRef) directory:localPath filename:fileName];

} enter image description here The memory was decreased, however, a new issue happened. My app was crashed because of over-released memory. Because the UIImage was released by CGImageRelease(), but ARC also tried to send a delloc message to the zombie object before the app end. How can I free the CGImageRef but not collide with ARC?

M.J. Zhuo
  • 11
  • 2

1 Answers1

0

Do not invoke CGImageRelease() on the CGImage property, since your code does not hold a incr ref to that object. You would only release in this case if your code explicitly incremented the ref someplace.

MoDJ
  • 4,309
  • 2
  • 30
  • 65
  • THX for your answer. But if I didn't release the CGImageRef, the memory will keep on growing, what can I do to release memory in each loop? – M.J. Zhuo Jun 17 '16 at 02:51
  • The code you posted above attempts to release with CGImageRelease() when the image is not held. Fix that first, then address the other problems in your code. For example, you can just pass a filename into a method, have that logic load the PNG and then release any held refs. As opposed to what you are doing now which is holding all the decompressed PNG images in memory. You simply cannot hold a lot of decompressed images in memory at the same time. Fix that and you should be better off. – MoDJ Jun 17 '16 at 21:58