Merge branch 'master' into gif_bk
This commit is contained in:
commit
c69e80286b
|
@ -1,3 +1,9 @@
|
|||
## [5.9.5 - 5.9 Patch, on Nov 13th, 2020](https://github.com/rs/SDWebImage/releases/tag/5.9.5)
|
||||
See [all tickets marked for the 5.9.5 release](https://github.com/SDWebImage/SDWebImage/milestone/81)
|
||||
|
||||
### Fixes
|
||||
- Add animationImages support when using SDAnimatedImageView #3113
|
||||
|
||||
## [5.9.4 - 5.9 Patch, on Oct 13th, 2020](https://github.com/rs/SDWebImage/releases/tag/5.9.4)
|
||||
See [all tickets marked for the 5.9.4 release](https://github.com/SDWebImage/SDWebImage/milestone/80)
|
||||
|
||||
|
|
|
@ -295,6 +295,9 @@ It's also recommend to use the module import syntax, available for CocoaPods(ena
|
|||
At this point your workspace should build without error. If you are having problem, post to the Issue and the
|
||||
community can help you solve it.
|
||||
|
||||
## Data Collection Practices
|
||||
As required by the [App privacy details on the App Store](https://developer.apple.com/app-store/app-privacy-details/), here's SDWebImage's list of [Data Collection Practices](https://sdwebimage.github.io/DataCollection/index.html).
|
||||
|
||||
## Author
|
||||
- [Olivier Poitrey](https://github.com/rs)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'SDWebImage'
|
||||
s.version = '5.9.4'
|
||||
s.version = '5.9.5'
|
||||
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.ios.deployment_target = '8.0'
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#import "SDInternalMacros.h"
|
||||
|
||||
@interface SDAnimatedImagePlayer () {
|
||||
SD_LOCK_DECLARE(_lock);
|
||||
NSRunLoopMode _runLoopMode;
|
||||
}
|
||||
|
||||
|
@ -27,7 +28,6 @@
|
|||
@property (nonatomic, assign) BOOL shouldReverse;
|
||||
@property (nonatomic, assign) NSUInteger maxBufferCount;
|
||||
@property (nonatomic, strong) NSOperationQueue *fetchQueue;
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
@property (nonatomic, strong) SDDisplayLink *displayLink;
|
||||
|
||||
@end
|
||||
|
@ -47,6 +47,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
|
||||
|
@ -71,7 +72,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) {
|
||||
|
@ -79,7 +80,7 @@
|
|||
[self.frameBuffer removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(self->_lock);
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -99,13 +100,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:)];
|
||||
|
@ -158,9 +152,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];
|
||||
}
|
||||
}
|
||||
|
@ -178,9 +172,9 @@
|
|||
}
|
||||
|
||||
- (void)clearFrameBuffer {
|
||||
SD_LOCK(self.lock);
|
||||
SD_LOCK(_lock);
|
||||
[_frameBuffer removeAllObjects];
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
}
|
||||
|
||||
#pragma mark - Animation Control
|
||||
|
@ -266,13 +260,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;
|
||||
|
@ -281,7 +275,7 @@
|
|||
if (self.frameBuffer.count == totalFrameCount) {
|
||||
bufferFull = YES;
|
||||
}
|
||||
SD_UNLOCK(self.lock);
|
||||
SD_UNLOCK(_lock);
|
||||
|
||||
// Update the current frame immediately
|
||||
self.currentFrame = currentFrame;
|
||||
|
@ -342,9 +336,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
|
||||
|
@ -359,9 +353,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];
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
/**
|
||||
A drop-in replacement for UIImageView/NSImageView, you can use this for animated image rendering.
|
||||
Call `setImage:` with `UIImage(NSImage)` which conform to `SDAnimatedImage` protocol will start animated image rendering. Call with normal UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering
|
||||
Call `setImage:` with `UIImage(NSImage)` which conforms to `SDAnimatedImage` protocol will start animated image rendering. Call with normal UIImage(NSImage) will back to normal UIImageView(NSImageView) rendering
|
||||
For UIKit: use `-startAnimating`, `-stopAnimating` to control animating. `isAnimating` to check animation state.
|
||||
For AppKit: use `-setAnimates:` to control animating, `animates` to check animation state. This view is layer-backed.
|
||||
*/
|
||||
|
@ -93,7 +93,7 @@
|
|||
@property (nonatomic, assign) BOOL resetFrameIndexWhenStopped;
|
||||
|
||||
/**
|
||||
If the image has more than one frame, set this value to `YES` will automatically
|
||||
If the image which conforms to `SDAnimatedImage` protocol has more than one frame, set this value to `YES` will automatically
|
||||
play/stop the animation when the view become visible/invisible.
|
||||
Default is YES.
|
||||
*/
|
||||
|
|
|
@ -418,7 +418,8 @@
|
|||
/// Check if it should be played
|
||||
- (void)checkPlay
|
||||
{
|
||||
if (self.autoPlayAnimatedImage) {
|
||||
// Only handle for SDAnimatedImage, leave UIAnimatedImage or animationImages for super implementation control
|
||||
if (self.player && self.autoPlayAnimatedImage) {
|
||||
[self updateShouldAnimate];
|
||||
if (self.shouldAnimate) {
|
||||
[self startAnimating];
|
||||
|
|
|
@ -341,7 +341,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
|
|||
* @param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
* @return The image for the given key, or nil if not found.
|
||||
*/
|
||||
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context;;
|
||||
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context;
|
||||
|
||||
#pragma mark - Remove Ops
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -93,7 +93,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeEmbedThumb
|
|||
But this may be useful for some custom coders, because some business logic may dependent on things other than image or image data information only.
|
||||
See `SDWebImageContext` for more detailed information.
|
||||
*/
|
||||
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext API_DEPRECATED("The coder component will be seperated from Core subspec in the future. Update your code to not rely on this context option.", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));;
|
||||
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext API_DEPRECATED("The coder component will be seperated from Core subspec in the future. Update your code to not rely on this context option.", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
|
||||
|
||||
#pragma mark - Coder
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -655,7 +655,7 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
|
|||
return nil;
|
||||
}
|
||||
image.sd_imageFormat = self.class.imageFormat;
|
||||
image.sd_isDecoded = YES;;
|
||||
image.sd_isDecoded = YES;
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS
|
|||
*/
|
||||
@protocol SDImageLoader <NSObject>
|
||||
|
||||
@required
|
||||
/**
|
||||
Whether current image loader supports to load the provide image URL.
|
||||
This will be checked every time a new image request come for loader. If this return NO, we will mark this image load as failed. If return YES, we will start to call `requestImageWithURL:options:context:progress:completed:`.
|
||||
|
@ -67,8 +68,23 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS
|
|||
@param url The image URL to be loaded.
|
||||
@return YES to continue download, NO to stop download.
|
||||
*/
|
||||
- (BOOL)canRequestImageForURL:(nullable NSURL *)url;
|
||||
- (BOOL)canRequestImageForURL:(nullable NSURL *)url API_DEPRECATED("Use canRequestImageForURL:options:context: instead", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
|
||||
|
||||
@optional
|
||||
/**
|
||||
Whether current image loader supports to load the provide image URL, with associated options and context.
|
||||
This will be checked every time a new image request come for loader. If this return NO, we will mark this image load as failed. If return YES, we will start to call `requestImageWithURL:options:context:progress:completed:`.
|
||||
|
||||
@param url The image URL to be loaded.
|
||||
@param options A mask to specify options to use for this request
|
||||
@param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
@return YES to continue download, NO to stop download.
|
||||
*/
|
||||
- (BOOL)canRequestImageForURL:(nullable NSURL *)url
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
@required
|
||||
/**
|
||||
Load the image and image data with the given URL and return the image data. You're responsible for producing the image instance.
|
||||
|
||||
|
@ -96,6 +112,22 @@ FOUNDATION_EXPORT UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NS
|
|||
@return Whether to block this url or not. Return YES to mark this URL as failed.
|
||||
*/
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(nonnull NSURL *)url
|
||||
error:(nonnull NSError *)error;
|
||||
error:(nonnull NSError *)error API_DEPRECATED("Use shouldBlockFailedURLWithURL:error:options:context: instead", macos(10.10, API_TO_BE_DEPRECATED), ios(8.0, API_TO_BE_DEPRECATED), tvos(9.0, API_TO_BE_DEPRECATED), watchos(2.0, API_TO_BE_DEPRECATED));
|
||||
|
||||
@optional
|
||||
/**
|
||||
Whether the error from image loader should be marked indeed un-recoverable or not, with associated options and context.
|
||||
If this return YES, failed URL which does not using `SDWebImageRetryFailed` will be blocked into black list. Else not.
|
||||
|
||||
@param url The URL represent the image. Note this may not be a HTTP URL
|
||||
@param error The URL's loading error, from previous `requestImageWithURL:options:context:progress:completed:` completedBlock's error.
|
||||
@param options A mask to specify options to use for this request
|
||||
@param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
|
||||
@return Whether to block this url or not. Return YES to mark this URL as failed.
|
||||
*/
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(nonnull NSURL *)url
|
||||
error:(nonnull NSError *)error
|
||||
options:(SDWebImageOptions)options
|
||||
context:(nullable SDWebImageContext *)context;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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;
|
||||
|
@ -561,6 +562,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
@implementation SDWebImageDownloader (SDImageLoader)
|
||||
|
||||
- (BOOL)canRequestImageForURL:(NSURL *)url {
|
||||
return [self canRequestImageForURL:url options:0 context:nil];
|
||||
}
|
||||
|
||||
- (BOOL)canRequestImageForURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context {
|
||||
if (!url) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -596,6 +601,10 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
}
|
||||
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error {
|
||||
return [self shouldBlockFailedURLWithURL:url error:error options:0 context:nil];
|
||||
}
|
||||
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error options:(SDWebImageOptions)options context:(SDWebImageContext *)context {
|
||||
BOOL shouldBlockFailedURL;
|
||||
// Filter the error domain and check error codes
|
||||
if ([error.domain isEqualToString:SDWebImageErrorDomain]) {
|
||||
|
|
|
@ -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
|
||||
|
@ -378,7 +379,11 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
BOOL shouldDownload = !SD_OPTIONS_CONTAINS(options, SDWebImageFromCacheOnly);
|
||||
shouldDownload &= (!cachedImage || options & SDWebImageRefreshCached);
|
||||
shouldDownload &= (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]);
|
||||
shouldDownload &= [imageLoader canRequestImageForURL:url];
|
||||
if ([imageLoader respondsToSelector:@selector(canRequestImageForURL:options:context:)]) {
|
||||
shouldDownload &= [imageLoader canRequestImageForURL:url options:options context:context];
|
||||
} else {
|
||||
shouldDownload &= [imageLoader canRequestImageForURL:url];
|
||||
}
|
||||
if (shouldDownload) {
|
||||
if (cachedImage && options & SDWebImageRefreshCached) {
|
||||
// If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image
|
||||
|
@ -411,15 +416,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 +565,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
|
||||
|
@ -631,7 +636,11 @@ static id<SDImageLoader> _defaultImageLoader;
|
|||
if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) {
|
||||
shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error];
|
||||
} else {
|
||||
shouldBlockFailedURL = [imageLoader shouldBlockFailedURLWithURL:url error:error];
|
||||
if ([imageLoader respondsToSelector:@selector(shouldBlockFailedURLWithURL:error:options:context:)]) {
|
||||
shouldBlockFailedURL = [imageLoader shouldBlockFailedURLWithURL:url error:error options:options context:context];
|
||||
} else {
|
||||
shouldBlockFailedURL = [imageLoader shouldBlockFailedURLWithURL:url error:error];
|
||||
}
|
||||
}
|
||||
|
||||
return shouldBlockFailedURL;
|
||||
|
|
|
@ -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,44 @@
|
|||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <os/lock.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
#import "SDmetamacros.h"
|
||||
|
||||
#ifndef SD_LOCK_DECLARE
|
||||
#if TARGET_OS_MACCATALYST
|
||||
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock;
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef SD_LOCK_INIT
|
||||
#if TARGET_OS_MACCATALYST
|
||||
#define SD_LOCK_INIT(lock) lock = OS_UNFAIR_LOCK_INIT;
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef SD_LOCK
|
||||
#define SD_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
#if TARGET_OS_MACCATALYST
|
||||
#define SD_LOCK(lock) os_unfair_lock_lock(&lock);
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef SD_UNLOCK
|
||||
#define SD_UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||
#if TARGET_OS_MACCATALYST
|
||||
#define SD_UNLOCK(lock) os_unfair_lock_unlock(&lock);
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef SD_OPTIONS_CONTAINS
|
||||
|
|
|
@ -602,7 +602,27 @@ static BOOL _isCalled;
|
|||
expect(SDImageAPNGTestCoder.isCalled).equal(YES);
|
||||
}
|
||||
|
||||
- (void)test30AnimatedImagePlaybackModeReverse {
|
||||
#if SD_UIKIT
|
||||
- (void)test31AnimatedImageViewSetAnimationImages {
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
UIImage *image = [[UIImage alloc] initWithData:[self testJPEGData]];
|
||||
imageView.animationImages = @[image];
|
||||
expect(imageView.animationImages).notTo.beNil();
|
||||
}
|
||||
|
||||
- (void)test32AnimatedImageViewNotStopPlayingAnimationImagesWhenHidden {
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
[self.window addSubview:imageView];
|
||||
UIImage *image = [[UIImage alloc] initWithData:[self testJPEGData]];
|
||||
imageView.animationImages = @[image];
|
||||
[imageView startAnimating];
|
||||
expect(imageView.animating).beTruthy();
|
||||
imageView.hidden = YES;
|
||||
expect(imageView.animating).beTruthy();
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)test33AnimatedImagePlaybackModeReverse {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView playback reverse mode"];
|
||||
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
|
@ -636,7 +656,7 @@ static BOOL _isCalled;
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
- (void)test31AnimatedImagePlaybackModeBounce {
|
||||
- (void)test34AnimatedImagePlaybackModeBounce {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView playback bounce mode"];
|
||||
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
|
@ -687,7 +707,7 @@ static BOOL _isCalled;
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)test32AnimatedImagePlaybackModeReversedBounce{
|
||||
- (void)test35AnimatedImagePlaybackModeReversedBounce{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView playback reverse bounce mode"];
|
||||
|
||||
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
|
||||
|
@ -737,8 +757,6 @@ static BOOL _isCalled;
|
|||
}];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark - Helper
|
||||
- (UIWindow *)window {
|
||||
if (!_window) {
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
}
|
||||
|
||||
- (BOOL)canRequestImageForURL:(NSURL *)url {
|
||||
return [self canRequestImageForURL:url options:0 context:nil];
|
||||
}
|
||||
|
||||
- (BOOL)canRequestImageForURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -60,6 +64,10 @@
|
|||
}
|
||||
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error {
|
||||
return [self shouldBlockFailedURLWithURL:url error:error options:0 context:nil];
|
||||
}
|
||||
|
||||
- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error options:(SDWebImageOptions)options context:(SDWebImageContext *)context {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.9.4</string>
|
||||
<string>5.9.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.9.4</string>
|
||||
<string>5.9.5</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
|
Loading…
Reference in New Issue