From 097e01cf152b17e459ff2cc69266d5f13cbd8584 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Tue, 7 Jun 2016 15:40:43 -0700 Subject: [PATCH] Fix runaway NSData (#205) * Fix runaway NSData Previously we were generating all the frames of the GIF and dispatching to write the data to the disk. This presents a problem if the disk backs up though and it can end up with theoretically every frame in memory. Instead, generate a frame and write it one frame at a time. Slower, but prevents this runaway memory situation. * Early return on error, thans @rahul-malik & @timonus! --- Pod/Classes/PINAnimatedImageManager.m | 31 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Pod/Classes/PINAnimatedImageManager.m b/Pod/Classes/PINAnimatedImageManager.m index a57fcc2..55631bd 100644 --- a/Pod/Classes/PINAnimatedImageManager.m +++ b/Pod/Classes/PINAnimatedImageManager.m @@ -380,34 +380,41 @@ ERROR;}) \ }); } - CGImageRef frameImage = CGImageSourceCreateImageAtIndex(imageSource, frameIdx, (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : (__bridge NSNumber *)kCFBooleanFalse}); - if (frameImage == nil) { - NSError *frameImageError = [NSError errorWithDomain:kPINAnimatedImageErrorDomain code:PINAnimatedImageErrorImageFrameError userInfo:nil]; - HANDLE_PROCESSING_ERROR(frameImageError); - break; - } - Float32 duration = durations[frameIdx]; fileDuration += duration; - NSData *frameData = (__bridge_transfer NSData *)CGDataProviderCopyData(CGImageGetDataProvider(frameImage)); - NSAssert(frameData.length == width * height * kPINAnimatedImageComponentsPerPixel, @"data should be width * height * 4 bytes"); + dispatch_group_async(diskGroup, diskWriteQueue, ^{ + if (PROCESSING_ERROR) { + return; + } + + CGImageRef frameImage = CGImageSourceCreateImageAtIndex(imageSource, frameIdx, (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache : (__bridge NSNumber *)kCFBooleanFalse}); + if (frameImage == nil) { + NSError *frameImageError = [NSError errorWithDomain:kPINAnimatedImageErrorDomain code:PINAnimatedImageErrorImageFrameError userInfo:nil]; + HANDLE_PROCESSING_ERROR(frameImageError); + return; + } + + NSData *frameData = (__bridge_transfer NSData *)CGDataProviderCopyData(CGImageGetDataProvider(frameImage)); + NSAssert(frameData.length == width * height * kPINAnimatedImageComponentsPerPixel, @"data should be width * height * 4 bytes"); NSError *frameWriteError = [self writeFrameToFile:fileHandle duration:duration frameData:frameData]; HANDLE_PROCESSING_ERROR(frameWriteError); + + CGImageRelease(frameImage); }); - CGImageRelease(frameImage); frameCountForFile++; } } } else { completion(NO, nil, PROCESSING_ERROR); } - - CFRelease(imageSource); } dispatch_group_wait(diskGroup, DISPATCH_TIME_FOREVER); + if (imageSource) { + CFRelease(imageSource); + } //close the file handle PINLog(@"closing last file: %@", fileHandle);