Merge pull request #3149 from kinarobin/fix-ImageIO-encode/decode-crash

Don't encode/decode image when app will terminated
This commit is contained in:
DreamPiggy 2021-04-01 20:36:59 +08:00 committed by GitHub
commit aa2e264ffb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 11 deletions

View File

@ -41,16 +41,14 @@
return self;
}
- (NSArray<id<SDImageCoder>> *)coders
{
- (NSArray<id<SDImageCoder>> *)coders {
SD_LOCK(_codersLock);
NSArray<id<SDImageCoder>> *coders = [_imageCoders copy];
SD_UNLOCK(_codersLock);
return coders;
}
- (void)setCoders:(NSArray<id<SDImageCoder>> *)coders
{
- (void)setCoders:(NSArray<id<SDImageCoder>> *)coders {
SD_LOCK(_codersLock);
[_imageCoders removeAllObjects];
if (coders.count) {

View File

@ -29,6 +29,9 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
@implementation SDImageIOCoderFrame
@end
static BOOL willTerminated_;
static NSLock *terminatedLock_;
@implementation SDImageIOAnimatedCoder {
size_t _width, _height;
CGImageSourceRef _imageSource;
@ -42,8 +45,40 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
CGSize _thumbnailSize;
}
- (void)dealloc
{
+ (void)initialize {
if (self == SDImageIOAnimatedCoder.class) {
willTerminated_ = NO;
terminatedLock_ = [[NSLock alloc] init];
#if SD_UIKIT
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
#endif
#if SD_MAC
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:NSApplicationWillTerminateNotification
object:nil];
#endif
}
}
+ (void)applicationWillTerminate:(NSNotification *)note {
[terminatedLock_ lock];
willTerminated_ = YES;
[terminatedLock_ unlock];
}
+ (BOOL)willTerminated {
[terminatedLock_ lock];
BOOL willTerminated = willTerminated_;
[terminatedLock_ unlock];
return willTerminated;
}
- (void)dealloc {
if (_imageSource) {
CFRelease(_imageSource);
_imageSource = NULL;
@ -53,8 +88,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
#endif
}
- (void)didReceiveMemoryWarning:(NSNotification *)notification
{
- (void)didReceiveMemoryWarning:(NSNotification *)notification {
if (_imageSource) {
for (size_t i = 0; i < _frameCount; i++) {
CGImageSourceRemoveCacheAtIndex(_imageSource, i);
@ -188,6 +222,11 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
}
+ (UIImage *)createFrameAtIndex:(NSUInteger)index source:(CGImageSourceRef)source scale:(CGFloat)scale preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize options:(NSDictionary *)options {
// Earily return when application will be terminated.
if (self.willTerminated) {
return nil;
}
// Some options need to pass to `CGImageSourceCopyPropertiesAtIndex` before `CGImageSourceCreateImageAtIndex`, or ImageIO will ignore them because they parse once :)
// Parse the image properties
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, index, (__bridge CFDictionaryRef)options);
@ -375,11 +414,11 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
CGSize thumbnailSize = CGSizeZero;
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
if (thumbnailSizeValue != nil) {
#if SD_MAC
#if SD_MAC
thumbnailSize = thumbnailSizeValue.sizeValue;
#else
#else
thumbnailSize = thumbnailSizeValue.CGSizeValue;
#endif
#endif
}
_thumbnailSize = thumbnailSize;
BOOL preserveAspectRatio = YES;
@ -399,6 +438,10 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
if (_finished) {
return;
}
// Earily return when application will be terminated.
if (self.class.willTerminated) {
return;
}
_imageData = data;
_finished = finished;

View File

@ -311,6 +311,26 @@
}
}
- (void)test22DoNotDecodeImageWhenApplicationWillTerminate {
[[SDImageCodersManager sharedManager] addCoder:SDImageIOCoder.sharedCoder];
XCTestExpectation *expectation = [self expectationWithDescription:@"doNotDecodeImageWhenApplicationWillTerminate"];
NSString *testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImageLarge" ofType:@"png"];
NSData *testImageData = [NSData dataWithContentsOfFile:testImagePath];
[[SDImageCache sharedImageCache] storeImageDataToDisk:testImageData forKey:@"TestImageLarge"];
NSOperation *operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:@"TestImageLarge" done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
expect(data).to.equal(testImageData);
expect(image).to.beNil;
[[SDImageCache sharedImageCache] removeImageForKey:@"TestImageLarge" withCompletion:^{
[expectation fulfill];
}];
}];
expect(operation).toNot.beNil;
[operation start];
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillTerminateNotification object:nil];
[self waitForExpectationsWithCommonTimeout];
}
#pragma mark - Utils
- (void)verifyCoder:(id<SDImageCoder>)coder