Merge pull request #2274 from dreampiggy/fix_coders_array

Fix the thread-safe issue for coders manager.
This commit is contained in:
Bogdan Poplauschi 2018-04-19 08:34:43 +03:00 committed by GitHub
commit 8154d16bb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 35 deletions

View File

@ -39,7 +39,7 @@
/**
All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority
*/
@property (nonatomic, strong, readwrite, nullable) NSArray<id<SDWebImageCoder>> *coders;
@property (nonatomic, copy, readwrite, nullable) NSArray<id<SDWebImageCoder>> *coders;
/**
Add a new coder to the end of coders array. Which has the highest priority.

View File

@ -13,10 +13,12 @@
#import "SDWebImageWebPCoder.h"
#endif
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
@interface SDWebImageCodersManager ()
@property (strong, nonatomic, nonnull) NSMutableArray<SDWebImageCoder>* mutableCoders;
@property (strong, nonatomic, nullable) dispatch_queue_t mutableCodersAccessQueue;
@property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock;
@end
@ -34,11 +36,12 @@
- (instancetype)init {
if (self = [super init]) {
// initialize with default coders
_mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy];
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy];
#ifdef SD_WEBP
[_mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]];
[mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]];
#endif
_mutableCodersAccessQueue = dispatch_queue_create("com.hackemist.SDWebImageCodersManager", DISPATCH_QUEUE_CONCURRENT);
_coders = [mutableCoders copy];
_codersLock = dispatch_semaphore_create(1);
}
return self;
}
@ -46,36 +49,36 @@
#pragma mark - Coder IO operations
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder {
if ([coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
[self.mutableCoders addObject:coder];
});
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
if (!mutableCoders) {
mutableCoders = [NSMutableArray array];
}
[mutableCoders addObject:coder];
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder {
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
[self.mutableCoders removeObject:coder];
});
}
- (NSArray<id<SDWebImageCoder>> *)coders {
__block NSArray<id<SDWebImageCoder>> *sortedCoders = nil;
dispatch_sync(self.mutableCodersAccessQueue, ^{
sortedCoders = (NSArray<id<SDWebImageCoder>> *)[[[self.mutableCoders copy] reverseObjectEnumerator] allObjects];
});
return sortedCoders;
}
- (void)setCoders:(NSArray<id<SDWebImageCoder>> *)coders {
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
self.mutableCoders = [coders mutableCopy];
});
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
[mutableCoders removeObject:coder];
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}
#pragma mark - SDWebImageCoder
- (BOOL)canDecodeFromData:(NSData *)data {
for (id<SDWebImageCoder> coder in self.coders) {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:data]) {
return YES;
}
@ -84,7 +87,10 @@
}
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
for (id<SDWebImageCoder> coder in self.coders) {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canEncodeToFormat:format]) {
return YES;
}
@ -93,10 +99,10 @@
}
- (UIImage *)decodedImageWithData:(NSData *)data {
if (!data) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:data]) {
return [coder decodedImageWithData:data];
}
@ -110,7 +116,10 @@
if (!image) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:*data]) {
return [coder decompressedImageWithImage:image data:data options:optionsDict];
}
@ -122,7 +131,10 @@
if (!image) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canEncodeToFormat:format]) {
return [coder encodedDataWithImage:image format:format];
}