Merge pull request #2435 from dreampiggy/bugfix_progressive_race_condition

Fix a race condition during progressive animation load in SDAnimatedImageView
This commit is contained in:
Bogdan Poplauschi 2018-08-10 17:25:43 +03:00 committed by GitHub
commit 13207dd986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 12 deletions

View File

@ -621,20 +621,28 @@ static NSUInteger SDDeviceFreeMemory() {
return; return;
} }
if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) { if ([image conformsToProtocol:@protocol(SDAnimatedImage)] && image.sd_isIncremental) {
NSData *currentData = [((UIImage<SDAnimatedImage> *)image) animatedImageData]; UIImage *previousImage = self.image;
if (currentData) { if ([previousImage conformsToProtocol:@protocol(SDAnimatedImage)] && previousImage.sd_isIncremental) {
NSData *previousData; NSData *previousData = [((UIImage<SDAnimatedImage> *)previousImage) animatedImageData];
if ([self.image conformsToProtocol:@protocol(SDAnimatedImage)]) { NSData *currentData = [((UIImage<SDAnimatedImage> *)image) animatedImageData];
previousData = [((UIImage<SDAnimatedImage> *)self.image) animatedImageData]; // Check whether to use progressive rendering or not
}
// Check whether to use progressive coding // Warning: normally the `previousData` is same instance as `currentData` because our `SDAnimatedImage` class share the same `coder` instance internally. But there may be a race condition, that later retrived `currentData` is already been updated and it's not the same instance as `previousData`.
if (!previousData) { // And for protocol extensible design, we should not assume `SDAnimatedImage` protocol implementations always share same instance. So both of two reasons, we need that `rangeOfData` check.
// If previous data is nil if ([currentData isEqualToData:previousData]) {
self.isProgressive = YES; // If current data is the same data (or instance) as previous data
} else if ([currentData isEqualToData:previousData]) {
// If current data is equal to previous data
self.isProgressive = YES; self.isProgressive = YES;
} else if (currentData.length > previousData.length) {
// If current data is appended by previous data, use `NSDataSearchAnchored`
NSRange range = [currentData rangeOfData:previousData options:NSDataSearchAnchored range:NSMakeRange(0, previousData.length)];
if (range.location == 0 && range.length == previousData.length) {
// Contains hole previous data and they start with the same beginning
self.isProgressive = YES;
}
} }
} else {
// Previous image is not progressive, so start progressive rendering
self.isProgressive = YES;
} }
} }
} }