Follow Apple's best practice to use lock for array insert/remove thread safe, replace all current dispatch_semaphore usage into the os_unfair_lock, use OSSpinLock for iOS 10- lower firmware
This commit is contained in:
parent
2c8ed9a2f3
commit
cbbf3285e8
|
@ -13,6 +13,7 @@
|
|||
#import "SDInternalMacros.h"
|
||||
|
||||
@interface SDAnimatedImagePlayer () {
|
||||
SD_LOCK_DECLARE(_lock);
|
||||
NSRunLoopMode _runLoopMode;
|
||||
}
|
||||
|
||||
|
@ -26,7 +27,6 @@
|
|||
@property (nonatomic, assign) BOOL needsDisplayWhenImageBecomesAvailable;
|
||||
@property (nonatomic, assign) NSUInteger maxBufferCount;
|
||||
@property (nonatomic, strong) NSOperationQueue *fetchQueue;
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
@property (nonatomic, strong) SDDisplayLink *displayLink;
|
||||
|
||||
@end
|
||||
|
@ -46,6 +46,7 @@
|
|||
self.totalLoopCount = provider.animatedImageLoopCount;
|
||||
self.animatedProvider = provider;
|
||||
self.playbackRate = 1.0;
|
||||
SD_LOCK_INIT(_lock);
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
|
@ -70,7 +71,7 @@
|
|||
[_fetchQueue cancelAllOperations];
|
||||
[_fetchQueue addOperationWithBlock:^{
|
||||
NSNumber *currentFrameIndex = @(self.currentFrameIndex);
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(self->_lock);
|
||||
NSArray *keys = self.frameBuffer.allKeys;
|
||||
// only keep the next frame for later rendering
|
||||
for (NSNumber * key in keys) {
|
||||
|
@ -78,7 +79,7 @@
|
|||
[self.frameBuffer removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(self->_lock);
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -98,13 +99,6 @@
|
|||
return _frameBuffer;
|
||||
}
|
||||
|
||||
- (dispatch_semaphore_t)lock {
|
||||
if (!_lock) {
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
}
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (SDDisplayLink *)displayLink {
|
||||
if (!_displayLink) {
|
||||
_displayLink = [SDDisplayLink displayLinkWithTarget:self selector:@selector(displayDidRefresh:)];
|
||||
|
@ -152,9 +146,9 @@
|
|||
#endif
|
||||
if (posterFrame) {
|
||||
self.currentFrame = posterFrame;
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(self->_lock);
|
||||
self.frameBuffer[@(self.currentFrameIndex)] = self.currentFrame;
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(self->_lock);
|
||||
[self handleFrameChange];
|
||||
}
|
||||
}
|
||||
|
@ -171,9 +165,9 @@
|
|||
}
|
||||
|
||||
- (void)clearFrameBuffer {
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(_lock);
|
||||
[_frameBuffer removeAllObjects];
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
}
|
||||
|
||||
#pragma mark - Animation Control
|
||||
|
@ -246,13 +240,13 @@
|
|||
BOOL bufferFull = NO;
|
||||
if (self.needsDisplayWhenImageBecomesAvailable) {
|
||||
UIImage *currentFrame;
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(_lock);
|
||||
currentFrame = self.frameBuffer[@(currentFrameIndex)];
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
|
||||
// Update the current frame
|
||||
if (currentFrame) {
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(_lock);
|
||||
// Remove the frame buffer if need
|
||||
if (self.frameBuffer.count > self.maxBufferCount) {
|
||||
self.frameBuffer[@(currentFrameIndex)] = nil;
|
||||
|
@ -261,7 +255,7 @@
|
|||
if (self.frameBuffer.count == totalFrameCount) {
|
||||
bufferFull = YES;
|
||||
}
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
|
||||
// Update the current frame immediately
|
||||
self.currentFrame = currentFrame;
|
||||
|
@ -322,9 +316,9 @@
|
|||
// Or, most cases, the decode speed is faster than render speed, we fetch next frame
|
||||
NSUInteger fetchFrameIndex = self.bufferMiss? currentFrameIndex : nextFrameIndex;
|
||||
UIImage *fetchFrame;
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(_lock);
|
||||
fetchFrame = self.bufferMiss? nil : self.frameBuffer[@(nextFrameIndex)];
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
|
||||
if (!fetchFrame && !bufferFull && self.fetchQueue.operationCount == 0) {
|
||||
// Prefetch next frame in background queue
|
||||
|
@ -339,9 +333,9 @@
|
|||
|
||||
BOOL isAnimating = self.displayLink.isRunning;
|
||||
if (isAnimating) {
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(self->_lock);
|
||||
self.frameBuffer[@(fetchFrameIndex)] = frame;
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(self->_lock);
|
||||
}
|
||||
}];
|
||||
[self.fetchQueue addOperation:operation];
|
||||
|
|
|
@ -13,13 +13,12 @@
|
|||
|
||||
@interface SDImageCachesManager ()
|
||||
|
||||
@property (nonatomic, strong, nonnull) dispatch_semaphore_t cachesLock;
|
||||
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageCache>> *imageCaches;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDImageCachesManager
|
||||
{
|
||||
NSMutableArray<id<SDImageCache>> *_imageCaches;
|
||||
@implementation SDImageCachesManager {
|
||||
SD_LOCK_DECLARE(_cachesLock);
|
||||
}
|
||||
|
||||
+ (SDImageCachesManager *)sharedManager {
|
||||
|
@ -41,25 +40,25 @@
|
|||
self.clearOperationPolicy = SDImageCachesManagerOperationPolicyConcurrent;
|
||||
// initialize with default image caches
|
||||
_imageCaches = [NSMutableArray arrayWithObject:[SDImageCache sharedImageCache]];
|
||||
_cachesLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_cachesLock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<id<SDImageCache>> *)caches {
|
||||
SD_LOCK(self.cachesLock);
|
||||
SD_LOCK(_cachesLock);
|
||||
NSArray<id<SDImageCache>> *caches = [_imageCaches copy];
|
||||
SD_UNLOCK(self.cachesLock);
|
||||
SD_UNLOCK(_cachesLock);
|
||||
return caches;
|
||||
}
|
||||
|
||||
- (void)setCaches:(NSArray<id<SDImageCache>> *)caches {
|
||||
SD_LOCK(self.cachesLock);
|
||||
SD_LOCK(_cachesLock);
|
||||
[_imageCaches removeAllObjects];
|
||||
if (caches.count) {
|
||||
[_imageCaches addObjectsFromArray:caches];
|
||||
}
|
||||
SD_UNLOCK(self.cachesLock);
|
||||
SD_UNLOCK(_cachesLock);
|
||||
}
|
||||
|
||||
#pragma mark - Cache IO operations
|
||||
|
@ -68,18 +67,18 @@
|
|||
if (![cache conformsToProtocol:@protocol(SDImageCache)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.cachesLock);
|
||||
SD_LOCK(_cachesLock);
|
||||
[_imageCaches addObject:cache];
|
||||
SD_UNLOCK(self.cachesLock);
|
||||
SD_UNLOCK(_cachesLock);
|
||||
}
|
||||
|
||||
- (void)removeCache:(id<SDImageCache>)cache {
|
||||
if (![cache conformsToProtocol:@protocol(SDImageCache)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.cachesLock);
|
||||
SD_LOCK(_cachesLock);
|
||||
[_imageCaches removeObject:cache];
|
||||
SD_UNLOCK(self.cachesLock);
|
||||
SD_UNLOCK(_cachesLock);
|
||||
}
|
||||
|
||||
#pragma mark - SDImageCache
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
|
||||
@interface SDImageCodersManager ()
|
||||
|
||||
@property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock;
|
||||
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageCoder>> *imageCoders;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDImageCodersManager
|
||||
{
|
||||
NSMutableArray<id<SDImageCoder>> *_imageCoders;
|
||||
@implementation SDImageCodersManager {
|
||||
SD_LOCK_DECLARE(_codersLock);
|
||||
}
|
||||
|
||||
+ (nonnull instancetype)sharedManager {
|
||||
|
@ -37,27 +36,27 @@
|
|||
if (self = [super init]) {
|
||||
// initialize with default coders
|
||||
_imageCoders = [NSMutableArray arrayWithArray:@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]];
|
||||
_codersLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_codersLock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<id<SDImageCoder>> *)coders
|
||||
{
|
||||
SD_LOCK(self.codersLock);
|
||||
SD_LOCK(_codersLock);
|
||||
NSArray<id<SDImageCoder>> *coders = [_imageCoders copy];
|
||||
SD_UNLOCK(self.codersLock);
|
||||
SD_UNLOCK(_codersLock);
|
||||
return coders;
|
||||
}
|
||||
|
||||
- (void)setCoders:(NSArray<id<SDImageCoder>> *)coders
|
||||
{
|
||||
SD_LOCK(self.codersLock);
|
||||
SD_LOCK(_codersLock);
|
||||
[_imageCoders removeAllObjects];
|
||||
if (coders.count) {
|
||||
[_imageCoders addObjectsFromArray:coders];
|
||||
}
|
||||
SD_UNLOCK(self.codersLock);
|
||||
SD_UNLOCK(_codersLock);
|
||||
}
|
||||
|
||||
#pragma mark - Coder IO operations
|
||||
|
@ -66,18 +65,18 @@
|
|||
if (![coder conformsToProtocol:@protocol(SDImageCoder)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.codersLock);
|
||||
SD_LOCK(_codersLock);
|
||||
[_imageCoders addObject:coder];
|
||||
SD_UNLOCK(self.codersLock);
|
||||
SD_UNLOCK(_codersLock);
|
||||
}
|
||||
|
||||
- (void)removeCoder:(nonnull id<SDImageCoder>)coder {
|
||||
if (![coder conformsToProtocol:@protocol(SDImageCoder)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.codersLock);
|
||||
SD_LOCK(_codersLock);
|
||||
[_imageCoders removeObject:coder];
|
||||
SD_UNLOCK(self.codersLock);
|
||||
SD_UNLOCK(_codersLock);
|
||||
}
|
||||
|
||||
#pragma mark - SDImageCoder
|
||||
|
|
|
@ -12,13 +12,12 @@
|
|||
|
||||
@interface SDImageLoadersManager ()
|
||||
|
||||
@property (nonatomic, strong, nonnull) dispatch_semaphore_t loadersLock;
|
||||
@property (nonatomic, strong, nonnull) NSMutableArray<id<SDImageLoader>> *imageLoaders;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDImageLoadersManager
|
||||
{
|
||||
NSMutableArray<id<SDImageLoader>>* _imageLoaders;
|
||||
@implementation SDImageLoadersManager {
|
||||
SD_LOCK_DECLARE(_loadersLock);
|
||||
}
|
||||
|
||||
+ (SDImageLoadersManager *)sharedManager {
|
||||
|
@ -35,25 +34,25 @@
|
|||
if (self) {
|
||||
// initialize with default image loaders
|
||||
_imageLoaders = [NSMutableArray arrayWithObject:[SDWebImageDownloader sharedDownloader]];
|
||||
_loadersLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_loadersLock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<id<SDImageLoader>> *)loaders {
|
||||
SD_LOCK(self.loadersLock);
|
||||
SD_LOCK(_loadersLock);
|
||||
NSArray<id<SDImageLoader>>* loaders = [_imageLoaders copy];
|
||||
SD_UNLOCK(self.loadersLock);
|
||||
SD_UNLOCK(_loadersLock);
|
||||
return loaders;
|
||||
}
|
||||
|
||||
- (void)setLoaders:(NSArray<id<SDImageLoader>> *)loaders {
|
||||
SD_LOCK(self.loadersLock);
|
||||
SD_LOCK(_loadersLock);
|
||||
[_imageLoaders removeAllObjects];
|
||||
if (loaders.count) {
|
||||
[_imageLoaders addObjectsFromArray:loaders];
|
||||
}
|
||||
SD_UNLOCK(self.loadersLock);
|
||||
SD_UNLOCK(_loadersLock);
|
||||
}
|
||||
|
||||
#pragma mark - Loader Property
|
||||
|
@ -62,18 +61,18 @@
|
|||
if (![loader conformsToProtocol:@protocol(SDImageLoader)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.loadersLock);
|
||||
SD_LOCK(_loadersLock);
|
||||
[_imageLoaders addObject:loader];
|
||||
SD_UNLOCK(self.loadersLock);
|
||||
SD_UNLOCK(_loadersLock);
|
||||
}
|
||||
|
||||
- (void)removeLoader:(id<SDImageLoader>)loader {
|
||||
if (![loader conformsToProtocol:@protocol(SDImageLoader)]) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.loadersLock);
|
||||
SD_LOCK(_loadersLock);
|
||||
[_imageLoaders removeObject:loader];
|
||||
SD_UNLOCK(self.loadersLock);
|
||||
SD_UNLOCK(_loadersLock);
|
||||
}
|
||||
|
||||
#pragma mark - SDImageLoader
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
|
||||
static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
||||
|
||||
@interface SDMemoryCache <KeyType, ObjectType> ()
|
||||
@interface SDMemoryCache <KeyType, ObjectType> () {
|
||||
#if SD_UIKIT
|
||||
SD_LOCK_DECLARE(_weakCacheLock); // a lock to keep the access to `weakCache` thread-safe
|
||||
#endif
|
||||
}
|
||||
|
||||
@property (nonatomic, strong, nullable) SDImageCacheConfig *config;
|
||||
#if SD_UIKIT
|
||||
@property (nonatomic, strong, nonnull) NSMapTable<KeyType, ObjectType> *weakCache; // strong-weak cache
|
||||
@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe
|
||||
#endif
|
||||
@end
|
||||
|
||||
|
@ -61,7 +64,7 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
|||
|
||||
#if SD_UIKIT
|
||||
self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];
|
||||
self.weakCacheLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_weakCacheLock);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(didReceiveMemoryWarning:)
|
||||
|
@ -85,9 +88,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
|||
}
|
||||
if (key && obj) {
|
||||
// Store weak cache
|
||||
SD_LOCK(self.weakCacheLock);
|
||||
SD_LOCK(_weakCacheLock);
|
||||
[self.weakCache setObject:obj forKey:key];
|
||||
SD_UNLOCK(self.weakCacheLock);
|
||||
SD_UNLOCK(_weakCacheLock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,9 +101,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
|||
}
|
||||
if (key && !obj) {
|
||||
// Check weak cache
|
||||
SD_LOCK(self.weakCacheLock);
|
||||
SD_LOCK(_weakCacheLock);
|
||||
obj = [self.weakCache objectForKey:key];
|
||||
SD_UNLOCK(self.weakCacheLock);
|
||||
SD_UNLOCK(_weakCacheLock);
|
||||
if (obj) {
|
||||
// Sync cache
|
||||
NSUInteger cost = 0;
|
||||
|
@ -120,9 +123,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
|||
}
|
||||
if (key) {
|
||||
// Remove weak cache
|
||||
SD_LOCK(self.weakCacheLock);
|
||||
SD_LOCK(_weakCacheLock);
|
||||
[self.weakCache removeObjectForKey:key];
|
||||
SD_UNLOCK(self.weakCacheLock);
|
||||
SD_UNLOCK(_weakCacheLock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,9 +135,9 @@ static void * SDMemoryCacheContext = &SDMemoryCacheContext;
|
|||
return;
|
||||
}
|
||||
// Manually remove should also remove weak cache
|
||||
SD_LOCK(self.weakCacheLock);
|
||||
SD_LOCK(_weakCacheLock);
|
||||
[self.weakCache removeAllObjects];
|
||||
SD_UNLOCK(self.weakCacheLock);
|
||||
SD_UNLOCK(_weakCacheLock);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -40,15 +40,16 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
|
||||
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, NSOperation<SDWebImageDownloaderOperation> *> *URLOperations;
|
||||
@property (strong, nonatomic, nullable) NSMutableDictionary<NSString *, NSString *> *HTTPHeaders;
|
||||
@property (strong, nonatomic, nonnull) dispatch_semaphore_t HTTPHeadersLock; // A lock to keep the access to `HTTPHeaders` thread-safe
|
||||
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // A lock to keep the access to `URLOperations` thread-safe
|
||||
|
||||
// The session in which data tasks will run
|
||||
@property (strong, nonatomic) NSURLSession *session;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDownloader
|
||||
@implementation SDWebImageDownloader {
|
||||
SD_LOCK_DECLARE(_HTTPHeadersLock); // A lock to keep the access to `HTTPHeaders` thread-safe
|
||||
SD_LOCK_DECLARE(_operationsLock); // A lock to keep the access to `URLOperations` thread-safe
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
|
||||
|
@ -120,8 +121,8 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
}
|
||||
headerDictionary[@"Accept"] = @"image/*,*/*;q=0.8";
|
||||
_HTTPHeaders = headerDictionary;
|
||||
_HTTPHeadersLock = dispatch_semaphore_create(1);
|
||||
_operationsLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_HTTPHeadersLock);
|
||||
SD_LOCK_INIT(_operationsLock);
|
||||
NSURLSessionConfiguration *sessionConfiguration = _config.sessionConfiguration;
|
||||
if (!sessionConfiguration) {
|
||||
sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
|
@ -161,18 +162,18 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
if (!field) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.HTTPHeadersLock);
|
||||
SD_LOCK(_HTTPHeadersLock);
|
||||
[self.HTTPHeaders setValue:value forKey:field];
|
||||
SD_UNLOCK(self.HTTPHeadersLock);
|
||||
SD_UNLOCK(_HTTPHeadersLock);
|
||||
}
|
||||
|
||||
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
|
||||
if (!field) {
|
||||
return nil;
|
||||
}
|
||||
SD_LOCK(self.HTTPHeadersLock);
|
||||
SD_LOCK(_HTTPHeadersLock);
|
||||
NSString *value = [self.HTTPHeaders objectForKey:field];
|
||||
SD_UNLOCK(self.HTTPHeadersLock);
|
||||
SD_UNLOCK(_HTTPHeadersLock);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -202,14 +203,14 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
return nil;
|
||||
}
|
||||
|
||||
SD_LOCK(self.operationsLock);
|
||||
SD_LOCK(_operationsLock);
|
||||
id downloadOperationCancelToken;
|
||||
NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
|
||||
// There is a case that the operation may be marked as finished or cancelled, but not been removed from `self.URLOperations`.
|
||||
if (!operation || operation.isFinished || operation.isCancelled) {
|
||||
operation = [self createDownloaderOperationWithUrl:url options:options context:context];
|
||||
if (!operation) {
|
||||
SD_UNLOCK(self.operationsLock);
|
||||
SD_UNLOCK(_operationsLock);
|
||||
if (completedBlock) {
|
||||
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}];
|
||||
completedBlock(nil, nil, error, YES);
|
||||
|
@ -222,9 +223,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
if (!self) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.operationsLock);
|
||||
SD_LOCK(self->_operationsLock);
|
||||
[self.URLOperations removeObjectForKey:url];
|
||||
SD_UNLOCK(self.operationsLock);
|
||||
SD_UNLOCK(self->_operationsLock);
|
||||
};
|
||||
self.URLOperations[url] = operation;
|
||||
// Add the handlers before submitting to operation queue, avoid the race condition that operation finished before setting handlers.
|
||||
|
@ -248,7 +249,7 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
}
|
||||
}
|
||||
}
|
||||
SD_UNLOCK(self.operationsLock);
|
||||
SD_UNLOCK(_operationsLock);
|
||||
|
||||
SDWebImageDownloadToken *token = [[SDWebImageDownloadToken alloc] initWithDownloadOperation:operation];
|
||||
token.url = url;
|
||||
|
@ -271,9 +272,9 @@ static void * SDWebImageDownloaderContext = &SDWebImageDownloaderContext;
|
|||
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval];
|
||||
mutableRequest.HTTPShouldHandleCookies = SD_OPTIONS_CONTAINS(options, SDWebImageDownloaderHandleCookies);
|
||||
mutableRequest.HTTPShouldUsePipelining = YES;
|
||||
SD_LOCK(self.HTTPHeadersLock);
|
||||
SD_LOCK(_HTTPHeadersLock);
|
||||
mutableRequest.allHTTPHeaderFields = self.HTTPHeaders;
|
||||
SD_UNLOCK(self.HTTPHeadersLock);
|
||||
SD_UNLOCK(_HTTPHeadersLock);
|
||||
|
||||
// Context Option
|
||||
SDWebImageMutableContext *mutableContext;
|
||||
|
|
|
@ -26,14 +26,15 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
|
||||
@end
|
||||
|
||||
@interface SDWebImageManager ()
|
||||
@interface SDWebImageManager () {
|
||||
SD_LOCK_DECLARE(_failedURLsLock); // a lock to keep the access to `failedURLs` thread-safe
|
||||
SD_LOCK_DECLARE(_runningOperationsLock); // a lock to keep the access to `runningOperations` thread-safe
|
||||
}
|
||||
|
||||
@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache;
|
||||
@property (strong, nonatomic, readwrite, nonnull) id<SDImageLoader> imageLoader;
|
||||
@property (strong, nonatomic, nonnull) NSMutableSet<NSURL *> *failedURLs;
|
||||
@property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe
|
||||
@property (strong, nonatomic, nonnull) NSMutableSet<SDWebImageCombinedOperation *> *runningOperations;
|
||||
@property (strong, nonatomic, nonnull) dispatch_semaphore_t runningOperationsLock; // a lock to keep the access to `runningOperations` thread-safe
|
||||
|
||||
@end
|
||||
|
||||
|
@ -87,9 +88,9 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
_imageCache = cache;
|
||||
_imageLoader = loader;
|
||||
_failedURLs = [NSMutableSet new];
|
||||
_failedURLsLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_failedURLsLock);
|
||||
_runningOperations = [NSMutableSet new];
|
||||
_runningOperationsLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_runningOperationsLock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -188,9 +189,9 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
|
||||
BOOL isFailedUrl = NO;
|
||||
if (url) {
|
||||
SD_LOCK(self.failedURLsLock);
|
||||
SD_LOCK(_failedURLsLock);
|
||||
isFailedUrl = [self.failedURLs containsObject:url];
|
||||
SD_UNLOCK(self.failedURLsLock);
|
||||
SD_UNLOCK(_failedURLsLock);
|
||||
}
|
||||
|
||||
if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
|
||||
|
@ -200,9 +201,9 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
return operation;
|
||||
}
|
||||
|
||||
SD_LOCK(self.runningOperationsLock);
|
||||
SD_LOCK(_runningOperationsLock);
|
||||
[self.runningOperations addObject:operation];
|
||||
SD_UNLOCK(self.runningOperationsLock);
|
||||
SD_UNLOCK(_runningOperationsLock);
|
||||
|
||||
// Preprocess the options and context arg to decide the final the result for manager
|
||||
SDWebImageOptionsResult *result = [self processedResultForURL:url options:options context:context];
|
||||
|
@ -214,17 +215,17 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
}
|
||||
|
||||
- (void)cancelAll {
|
||||
SD_LOCK(self.runningOperationsLock);
|
||||
SD_LOCK(_runningOperationsLock);
|
||||
NSSet<SDWebImageCombinedOperation *> *copiedOperations = [self.runningOperations copy];
|
||||
SD_UNLOCK(self.runningOperationsLock);
|
||||
SD_UNLOCK(_runningOperationsLock);
|
||||
[copiedOperations makeObjectsPerformSelector:@selector(cancel)]; // This will call `safelyRemoveOperationFromRunning:` and remove from the array
|
||||
}
|
||||
|
||||
- (BOOL)isRunning {
|
||||
BOOL isRunning = NO;
|
||||
SD_LOCK(self.runningOperationsLock);
|
||||
SD_LOCK(_runningOperationsLock);
|
||||
isRunning = (self.runningOperations.count > 0);
|
||||
SD_UNLOCK(self.runningOperationsLock);
|
||||
SD_UNLOCK(_runningOperationsLock);
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
|
@ -232,15 +233,15 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
if (!url) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.failedURLsLock);
|
||||
SD_LOCK(_failedURLsLock);
|
||||
[self.failedURLs removeObject:url];
|
||||
SD_UNLOCK(self.failedURLsLock);
|
||||
SD_UNLOCK(_failedURLsLock);
|
||||
}
|
||||
|
||||
- (void)removeAllFailedURLs {
|
||||
SD_LOCK(self.failedURLsLock);
|
||||
SD_LOCK(_failedURLsLock);
|
||||
[self.failedURLs removeAllObjects];
|
||||
SD_UNLOCK(self.failedURLsLock);
|
||||
SD_UNLOCK(_failedURLsLock);
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
@ -411,15 +412,15 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
BOOL shouldBlockFailedURL = [self shouldBlockFailedURLWithURL:url error:error options:options context:context];
|
||||
|
||||
if (shouldBlockFailedURL) {
|
||||
SD_LOCK(self.failedURLsLock);
|
||||
SD_LOCK(self->_failedURLsLock);
|
||||
[self.failedURLs addObject:url];
|
||||
SD_UNLOCK(self.failedURLsLock);
|
||||
SD_UNLOCK(self->_failedURLsLock);
|
||||
}
|
||||
} else {
|
||||
if ((options & SDWebImageRetryFailed)) {
|
||||
SD_LOCK(self.failedURLsLock);
|
||||
SD_LOCK(self->_failedURLsLock);
|
||||
[self.failedURLs removeObject:url];
|
||||
SD_UNLOCK(self.failedURLsLock);
|
||||
SD_UNLOCK(self->_failedURLsLock);
|
||||
}
|
||||
// Continue store cache process
|
||||
[self callStoreCacheProcessForOperation:operation url:url options:options context:context downloadedImage:downloadedImage downloadedData:downloadedData finished:finished progress:progressBlock completed:completedBlock];
|
||||
|
@ -560,9 +561,9 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
if (!operation) {
|
||||
return;
|
||||
}
|
||||
SD_LOCK(self.runningOperationsLock);
|
||||
SD_LOCK(_runningOperationsLock);
|
||||
[self.runningOperations removeObject:operation];
|
||||
SD_UNLOCK(self.runningOperationsLock);
|
||||
SD_UNLOCK(_runningOperationsLock);
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
unsigned long _totalCount;
|
||||
|
||||
// Used to ensure NSPointerArray thread safe
|
||||
dispatch_semaphore_t _prefetchOperationsLock;
|
||||
dispatch_semaphore_t _loadOperationsLock;
|
||||
SD_LOCK_DECLARE(_prefetchOperationsLock)
|
||||
SD_LOCK_DECLARE(_loadOperationsLock);
|
||||
}
|
||||
|
||||
@property (nonatomic, copy, readwrite) NSArray<NSURL *> *urls;
|
||||
|
@ -268,8 +268,8 @@
|
|||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_prefetchOperationsLock = dispatch_semaphore_create(1);
|
||||
_loadOperationsLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_prefetchOperationsLock);
|
||||
SD_LOCK_INIT(_loadOperationsLock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ static NSArray *SDBundlePreferredScales() {
|
|||
}
|
||||
|
||||
@implementation SDImageAssetManager {
|
||||
dispatch_semaphore_t _lock;
|
||||
SD_LOCK_DECLARE(_lock);
|
||||
}
|
||||
|
||||
+ (instancetype)sharedAssetManager {
|
||||
|
@ -56,7 +56,7 @@ static NSArray *SDBundlePreferredScales() {
|
|||
valueOptions = NSPointerFunctionsStrongMemory;
|
||||
#endif
|
||||
_imageTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:valueOptions];
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_lock);
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
|
|
|
@ -9,9 +9,8 @@
|
|||
#import "SDImageCachesManagerOperation.h"
|
||||
#import "SDInternalMacros.h"
|
||||
|
||||
@implementation SDImageCachesManagerOperation
|
||||
{
|
||||
dispatch_semaphore_t _pendingCountLock;
|
||||
@implementation SDImageCachesManagerOperation {
|
||||
SD_LOCK_DECLARE(_pendingCountLock);
|
||||
}
|
||||
|
||||
@synthesize executing = _executing;
|
||||
|
@ -21,7 +20,7 @@
|
|||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_pendingCountLock = dispatch_semaphore_create(1);
|
||||
SD_LOCK_INIT(_pendingCountLock);
|
||||
_pendingCount = 0;
|
||||
}
|
||||
return self;
|
||||
|
|
|
@ -7,14 +7,28 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <os/lock.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
#import "SDmetamacros.h"
|
||||
|
||||
#ifndef SD_LOCK_DECLARE
|
||||
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \
|
||||
OSSpinLock lock##_deprecated;
|
||||
#endif
|
||||
|
||||
#ifndef SD_LOCK_INIT
|
||||
#define SD_LOCK_INIT(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) lock = OS_UNFAIR_LOCK_INIT; \
|
||||
else lock##_deprecated = OS_SPINLOCK_INIT;
|
||||
#endif
|
||||
|
||||
#ifndef SD_LOCK
|
||||
#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
#define SD_LOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_lock(&lock); \
|
||||
else OSSpinLockLock(&lock##_deprecated);
|
||||
#endif
|
||||
|
||||
#ifndef SD_UNLOCK
|
||||
#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||
#define SD_UNLOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_unlock(&lock); \
|
||||
else OSSpinLockUnlock(&lock##_deprecated);
|
||||
#endif
|
||||
|
||||
#ifndef SD_OPTIONS_CONTAINS
|
||||
|
|
Loading…
Reference in New Issue