Merge pull request #3576 from dreampiggy/feature_set_image_state_api

Add better support for stateful view (UIButton) for image URL/progres s state management
This commit is contained in:
DreamPiggy 2023-07-31 17:59:57 +08:00 committed by GitHub
commit 5ef6c83953
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 353 additions and 114 deletions

View File

@ -22,6 +22,10 @@
/* End PBXAggregateTarget section */ /* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
320797442A76287D00B17CF5 /* UIView+WebCacheState.h in Headers */ = {isa = PBXBuildFile; fileRef = 320797422A76287D00B17CF5 /* UIView+WebCacheState.h */; settings = {ATTRIBUTES = (Public, ); }; };
320797452A76287D00B17CF5 /* UIView+WebCacheState.m in Sources */ = {isa = PBXBuildFile; fileRef = 320797432A76287D00B17CF5 /* UIView+WebCacheState.m */; };
320797472A76288C00B17CF5 /* UIView+WebCacheState.m in Sources */ = {isa = PBXBuildFile; fileRef = 320797432A76287D00B17CF5 /* UIView+WebCacheState.m */; };
3207974C2A7628CB00B17CF5 /* UIView+WebCacheState.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 320797422A76287D00B17CF5 /* UIView+WebCacheState.h */; };
320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; }; 320CAE172086F50500CFFC80 /* SDWebImageError.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CAE132086F50500CFFC80 /* SDWebImageError.h */; settings = {ATTRIBUTES = (Public, ); }; };
320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE1B2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; };
320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; }; 320CAE1D2086F50500CFFC80 /* SDWebImageError.m in Sources */ = {isa = PBXBuildFile; fileRef = 320CAE142086F50500CFFC80 /* SDWebImageError.m */; };
@ -323,6 +327,7 @@
dstPath = include/SDWebImage; dstPath = include/SDWebImage;
dstSubfolderSpec = 16; dstSubfolderSpec = 16;
files = ( files = (
3207974C2A7628CB00B17CF5 /* UIView+WebCacheState.h in Copy Headers */,
325074F2296C546D00B730CF /* SDCallbackQueue.h in Copy Headers */, 325074F2296C546D00B730CF /* SDCallbackQueue.h in Copy Headers */,
32D9EE4B24AF259B00EAFDF4 /* SDImageAWebPCoder.h in Copy Headers */, 32D9EE4B24AF259B00EAFDF4 /* SDImageAWebPCoder.h in Copy Headers */,
328E9DE523A61DD30051C893 /* SDGraphicsImageRenderer.h in Copy Headers */, 328E9DE523A61DD30051C893 /* SDGraphicsImageRenderer.h in Copy Headers */,
@ -392,6 +397,8 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDAnimatedImageRep.h; path = Core/SDAnimatedImageRep.h; sourceTree = "<group>"; }; 320224B9203979BA00E9F285 /* SDAnimatedImageRep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDAnimatedImageRep.h; path = Core/SDAnimatedImageRep.h; sourceTree = "<group>"; };
320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDAnimatedImageRep.m; path = Core/SDAnimatedImageRep.m; sourceTree = "<group>"; }; 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDAnimatedImageRep.m; path = Core/SDAnimatedImageRep.m; sourceTree = "<group>"; };
320797422A76287D00B17CF5 /* UIView+WebCacheState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCacheState.h"; path = "Core/UIView+WebCacheState.h"; sourceTree = "<group>"; };
320797432A76287D00B17CF5 /* UIView+WebCacheState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCacheState.m"; path = "Core/UIView+WebCacheState.m"; sourceTree = "<group>"; };
320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageError.h; path = Core/SDWebImageError.h; sourceTree = "<group>"; }; 320CAE132086F50500CFFC80 /* SDWebImageError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDWebImageError.h; path = Core/SDWebImageError.h; sourceTree = "<group>"; };
320CAE142086F50500CFFC80 /* SDWebImageError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageError.m; path = Core/SDWebImageError.m; sourceTree = "<group>"; }; 320CAE142086F50500CFFC80 /* SDWebImageError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDWebImageError.m; path = Core/SDWebImageError.m; sourceTree = "<group>"; };
321117A7296573680001FC2C /* SDCallbackQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDCallbackQueue.h; path = Core/SDCallbackQueue.h; sourceTree = "<group>"; }; 321117A7296573680001FC2C /* SDCallbackQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDCallbackQueue.h; path = Core/SDCallbackQueue.h; sourceTree = "<group>"; };
@ -824,6 +831,8 @@
4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */, 4397D2F51D0DE2DF00BB2784 /* NSImage+Compatibility.m */,
AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */, AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */,
AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */, AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */,
320797422A76287D00B17CF5 /* UIView+WebCacheState.h */,
320797432A76287D00B17CF5 /* UIView+WebCacheState.m */,
); );
name = Categories; name = Categories;
sourceTree = "<group>"; sourceTree = "<group>";
@ -979,6 +988,7 @@
32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */, 32C0FDE32013426C001B8F2D /* SDWebImageIndicator.h in Headers */,
32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */, 32F7C0712030114C00873181 /* SDImageTransformer.h in Headers */,
32E67311235765B500DB4987 /* SDDisplayLink.h in Headers */, 32E67311235765B500DB4987 /* SDDisplayLink.h in Headers */,
320797442A76287D00B17CF5 /* UIView+WebCacheState.h in Headers */,
325F7CC623893B2E00AEDFCC /* SDFileAttributeHelper.h in Headers */, 325F7CC623893B2E00AEDFCC /* SDFileAttributeHelper.h in Headers */,
4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */, 4A2CAE2D1AB4BB7500B6BC39 /* UIImage+GIF.h in Headers */,
4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */, 4A2CAE291AB4BB7500B6BC39 /* NSData+ImageContentType.h in Headers */,
@ -1209,6 +1219,7 @@
325F7CC723893B2E00AEDFCC /* SDFileAttributeHelper.m in Sources */, 325F7CC723893B2E00AEDFCC /* SDFileAttributeHelper.m in Sources */,
3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */, 3248475F201775F600AF9E5A /* SDAnimatedImageView.m in Sources */,
32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */, 32D1222C2080B2EB003685A3 /* SDImageCachesManager.m in Sources */,
320797452A76287D00B17CF5 /* UIView+WebCacheState.m in Sources */,
32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */, 32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */, 43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
32A09E42233358B700339F9D /* SDImageIOAnimatedCoder.m in Sources */, 32A09E42233358B700339F9D /* SDImageIOAnimatedCoder.m in Sources */,
@ -1269,6 +1280,7 @@
32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */, 32F7C0752030114C00873181 /* SDImageTransformer.m in Sources */,
3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */, 3237F9EB20161AE000A88143 /* NSImage+Compatibility.m in Sources */,
32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */, 32C0FDE72013426C001B8F2D /* SDWebImageIndicator.m in Sources */,
320797472A76288C00B17CF5 /* UIView+WebCacheState.m in Sources */,
32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */, 32B5CC63222F8B70005EB74E /* SDAsyncBlockOperation.m in Sources */,
32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */, 32F21B5720788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
3237321629F8D0E200D1DA41 /* SDImageFramePool.m in Sources */, 3237321629F8D0E200D1DA41 /* SDImageFramePool.m in Sources */,

View File

@ -12,11 +12,10 @@
#import "objc/runtime.h" #import "objc/runtime.h"
#import "UIView+WebCacheOperation.h" #import "UIView+WebCacheOperation.h"
#import "UIView+WebCacheState.h"
#import "UIView+WebCache.h" #import "UIView+WebCache.h"
#import "SDInternalMacros.h" #import "SDInternalMacros.h"
static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageOperation";
@implementation NSButton (WebCache) @implementation NSButton (WebCache)
#pragma mark - Image #pragma mark - Image
@ -59,7 +58,6 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO
context:(nullable SDWebImageContext *)context context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock { completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentImageURL = url;
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:placeholder placeholderImage:placeholder
options:options options:options
@ -113,15 +111,13 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO
context:(nullable SDWebImageContext *)context context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock { completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentAlternateImageURL = url;
SDWebImageMutableContext *mutableContext; SDWebImageMutableContext *mutableContext;
if (context) { if (context) {
mutableContext = [context mutableCopy]; mutableContext = [context mutableCopy];
} else { } else {
mutableContext = [NSMutableDictionary dictionary]; mutableContext = [NSMutableDictionary dictionary];
} }
mutableContext[SDWebImageContextSetImageOperationKey] = SDAlternateImageOperationKey; mutableContext[SDWebImageContextSetImageOperationKey] = @keypath(self, alternateImage);
@weakify(self); @weakify(self);
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:placeholder placeholderImage:placeholder
@ -142,29 +138,23 @@ static NSString * const SDAlternateImageOperationKey = @"NSButtonAlternateImageO
#pragma mark - Cancel #pragma mark - Cancel
- (void)sd_cancelCurrentImageLoad { - (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; [self sd_cancelImageLoadOperationWithKey:nil];
} }
- (void)sd_cancelCurrentAlternateImageLoad { - (void)sd_cancelCurrentAlternateImageLoad {
[self sd_cancelImageLoadOperationWithKey:SDAlternateImageOperationKey]; [self sd_cancelImageLoadOperationWithKey:@keypath(self, alternateImage)];
} }
#pragma mark - Private #pragma mark - State
- (NSURL *)sd_currentImageURL { - (NSURL *)sd_currentImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentImageURL)); return [self sd_imageLoadStateForKey:nil].url;
} }
- (void)setSd_currentImageURL:(NSURL *)sd_currentImageURL { #pragma mark - Alternate State
objc_setAssociatedObject(self, @selector(sd_currentImageURL), sd_currentImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSURL *)sd_currentAlternateImageURL { - (NSURL *)sd_currentAlternateImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentAlternateImageURL)); return [self sd_imageLoadStateForKey:@keypath(self, alternateImage)].url;
}
- (void)setSd_currentAlternateImageURL:(NSURL *)sd_currentAlternateImageURL {
objc_setAssociatedObject(self, @selector(sd_currentAlternateImageURL), sd_currentAlternateImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} }
@end @end

View File

@ -21,6 +21,7 @@
/** /**
* Get the current image URL. * Get the current image URL.
* This simply translate to `[self sd_imageURLForState:self.state]` from v5.17.0
*/ */
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL; @property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL;
@ -31,6 +32,13 @@
*/ */
- (nullable NSURL *)sd_imageURLForState:(UIControlState)state; - (nullable NSURL *)sd_imageURLForState:(UIControlState)state;
/**
* Get the image operation key for a control state.
*
* @param state Which state you want to know the URL for. The values are described in UIControlState.
*/
- (nonnull NSString *)sd_imageOperationKeyForState:(UIControlState)state;
/** /**
* Set the button `image` with an `url`. * Set the button `image` with an `url`.
* *
@ -202,6 +210,13 @@
*/ */
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentBackgroundImageURL; @property (nonatomic, strong, readonly, nullable) NSURL *sd_currentBackgroundImageURL;
/**
* Get the background image operation key for a control state.
*
* @param state Which state you want to know the URL for. The values are described in UIControlState.
*/
- (nonnull NSString *)sd_backgroundImageOperationKeyForState:(UIControlState)state;
/** /**
* Get the background image URL for a control state. * Get the background image URL for a control state.
* *

View File

@ -12,47 +12,14 @@
#import "objc/runtime.h" #import "objc/runtime.h"
#import "UIView+WebCacheOperation.h" #import "UIView+WebCacheOperation.h"
#import "UIView+WebCacheState.h"
#import "UIView+WebCache.h" #import "UIView+WebCache.h"
#import "SDInternalMacros.h" #import "SDInternalMacros.h"
static char imageURLStorageKey;
typedef NSMutableDictionary<NSString *, NSURL *> SDStateImageURLDictionary;
static inline NSString * imageURLKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"image_%lu", (unsigned long)state];
}
static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"backgroundImage_%lu", (unsigned long)state];
}
static inline NSString * imageOperationKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"UIButtonImageOperation%lu", (unsigned long)state];
}
static inline NSString * backgroundImageOperationKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"UIButtonBackgroundImageOperation%lu", (unsigned long)state];
}
@implementation UIButton (WebCache) @implementation UIButton (WebCache)
#pragma mark - Image #pragma mark - Image
- (nullable NSURL *)sd_currentImageURL {
NSURL *url = self.sd_imageURLStorage[imageURLKeyForState(self.state)];
if (!url) {
url = self.sd_imageURLStorage[imageURLKeyForState(UIControlStateNormal)];
}
return url;
}
- (nullable NSURL *)sd_imageURLForState:(UIControlState)state {
return self.sd_imageURLStorage[imageURLKeyForState(state)];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
[self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
} }
@ -92,19 +59,13 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat
context:(nullable SDWebImageContext *)context context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock { completed:(nullable SDExternalCompletionBlock)completedBlock {
if (!url) {
[self.sd_imageURLStorage removeObjectForKey:imageURLKeyForState(state)];
} else {
self.sd_imageURLStorage[imageURLKeyForState(state)] = url;
}
SDWebImageMutableContext *mutableContext; SDWebImageMutableContext *mutableContext;
if (context) { if (context) {
mutableContext = [context mutableCopy]; mutableContext = [context mutableCopy];
} else { } else {
mutableContext = [NSMutableDictionary dictionary]; mutableContext = [NSMutableDictionary dictionary];
} }
mutableContext[SDWebImageContextSetImageOperationKey] = imageOperationKeyForState(state); mutableContext[SDWebImageContextSetImageOperationKey] = [self sd_imageOperationKeyForState:state];
@weakify(self); @weakify(self);
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:placeholder placeholderImage:placeholder
@ -124,20 +85,6 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat
#pragma mark - Background Image #pragma mark - Background Image
- (nullable NSURL *)sd_currentBackgroundImageURL {
NSURL *url = self.sd_imageURLStorage[backgroundImageURLKeyForState(self.state)];
if (!url) {
url = self.sd_imageURLStorage[backgroundImageURLKeyForState(UIControlStateNormal)];
}
return url;
}
- (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state {
return self.sd_imageURLStorage[backgroundImageURLKeyForState(state)];
}
- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
[self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
} }
@ -177,19 +124,13 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat
context:(nullable SDWebImageContext *)context context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock { completed:(nullable SDExternalCompletionBlock)completedBlock {
if (!url) {
[self.sd_imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)];
} else {
self.sd_imageURLStorage[backgroundImageURLKeyForState(state)] = url;
}
SDWebImageMutableContext *mutableContext; SDWebImageMutableContext *mutableContext;
if (context) { if (context) {
mutableContext = [context mutableCopy]; mutableContext = [context mutableCopy];
} else { } else {
mutableContext = [NSMutableDictionary dictionary]; mutableContext = [NSMutableDictionary dictionary];
} }
mutableContext[SDWebImageContextSetImageOperationKey] = backgroundImageOperationKeyForState(state); mutableContext[SDWebImageContextSetImageOperationKey] = [self sd_backgroundImageOperationKeyForState:state];
@weakify(self); @weakify(self);
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:placeholder placeholderImage:placeholder
@ -210,23 +151,46 @@ static inline NSString * backgroundImageOperationKeyForState(UIControlState stat
#pragma mark - Cancel #pragma mark - Cancel
- (void)sd_cancelImageLoadForState:(UIControlState)state { - (void)sd_cancelImageLoadForState:(UIControlState)state {
[self sd_cancelImageLoadOperationWithKey:imageOperationKeyForState(state)]; [self sd_cancelImageLoadOperationWithKey:[self sd_imageOperationKeyForState:state]];
} }
- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state { - (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state {
[self sd_cancelImageLoadOperationWithKey:backgroundImageOperationKeyForState(state)]; [self sd_cancelImageLoadOperationWithKey:[self sd_backgroundImageOperationKeyForState:state]];
} }
#pragma mark - Private #pragma mark - State
- (SDStateImageURLDictionary *)sd_imageURLStorage { - (NSString *)sd_imageOperationKeyForState:(UIControlState)state {
SDStateImageURLDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey); return [NSString stringWithFormat:@"UIButtonImageOperation%lu", (unsigned long)state];
if (!storage) { }
storage = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &imageURLStorageKey, storage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - (NSString *)sd_backgroundImageOperationKeyForState:(UIControlState)state {
return [NSString stringWithFormat:@"UIButtonBackgroundImageOperation%lu", (unsigned long)state];
}
- (NSURL *)sd_currentImageURL {
NSURL *url = [self sd_imageURLForState:self.state];
if (!url) {
[self sd_imageURLForState:UIControlStateNormal];
} }
return url;
}
return storage; - (NSURL *)sd_imageURLForState:(UIControlState)state {
return [self sd_imageLoadStateForKey:[self sd_imageOperationKeyForState:state]].url;
}
#pragma mark - Background State
- (NSURL *)sd_currentBackgroundImageURL {
NSURL *url = [self sd_backgroundImageURLForState:self.state];
if (!url) {
url = [self sd_backgroundImageURLForState:UIControlStateNormal];
}
return url;
}
- (NSURL *)sd_backgroundImageURLForState:(UIControlState)state {
return [self sd_imageLoadStateForKey:[self sd_backgroundImageOperationKeyForState:state]].url;
} }
@end @end

View File

@ -17,6 +17,13 @@
*/ */
@interface UIImageView (HighlightedWebCache) @interface UIImageView (HighlightedWebCache)
#pragma mark - Highlighted Image
/**
* Get the current highlighted image URL.
*/
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentHighlightedImageURL;
/** /**
* Set the imageView `highlightedImage` with an `url`. * Set the imageView `highlightedImage` with an `url`.
* *
@ -124,6 +131,12 @@
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock; completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the current highlighted image load (for `UIImageView.highlighted`)
* @note For normal image, use `sd_cancelCurrentImageLoad`
*/
- (void)sd_cancelCurrentHighlightedImageLoad;
@end @end
#endif #endif

View File

@ -11,11 +11,10 @@
#if SD_UIKIT #if SD_UIKIT
#import "UIView+WebCacheOperation.h" #import "UIView+WebCacheOperation.h"
#import "UIView+WebCacheState.h"
#import "UIView+WebCache.h" #import "UIView+WebCache.h"
#import "SDInternalMacros.h" #import "SDInternalMacros.h"
static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOperationHighlighted";
@implementation UIImageView (HighlightedWebCache) @implementation UIImageView (HighlightedWebCache)
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url { - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url {
@ -54,7 +53,7 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera
} else { } else {
mutableContext = [NSMutableDictionary dictionary]; mutableContext = [NSMutableDictionary dictionary];
} }
mutableContext[SDWebImageContextSetImageOperationKey] = SDHighlightedImageOperationKey; mutableContext[SDWebImageContextSetImageOperationKey] = @keypath(self, highlightedImage);
[self sd_internalSetImageWithURL:url [self sd_internalSetImageWithURL:url
placeholderImage:nil placeholderImage:nil
options:options options:options
@ -71,6 +70,16 @@ static NSString * const SDHighlightedImageOperationKey = @"UIImageViewImageOpera
}]; }];
} }
#pragma mark - Highlighted State
- (NSURL *)sd_currentHighlightedImageURL {
return [self sd_imageLoadStateForKey:@keypath(self, highlightedImage)].url;
}
- (void)sd_cancelCurrentHighlightedImageLoad {
return [self sd_cancelImageLoadOperationWithKey:@keypath(self, highlightedImage)];
}
@end @end
#endif #endif

View File

@ -45,6 +45,15 @@
*/ */
@interface UIImageView (WebCache) @interface UIImageView (WebCache)
#pragma mark - Image State
/**
* Get the current image URL.
*/
@property (nonatomic, strong, readonly, nullable) NSURL *sd_currentImageURL;
#pragma mark - Image Loading
/** /**
* Set the imageView `image` with an `url`. * Set the imageView `image` with an `url`.
* *
@ -191,4 +200,10 @@
progress:(nullable SDImageLoaderProgressBlock)progressBlock progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock; completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the current normal image load (for `UIImageView.image`)
* @note For highlighted image, use `sd_cancelCurrentHighlightedImageLoad`
*/
- (void)sd_cancelCurrentImageLoad;
@end @end

View File

@ -9,6 +9,7 @@
#import "UIImageView+WebCache.h" #import "UIImageView+WebCache.h"
#import "objc/runtime.h" #import "objc/runtime.h"
#import "UIView+WebCacheOperation.h" #import "UIView+WebCacheOperation.h"
#import "UIView+WebCacheState.h"
#import "UIView+WebCache.h" #import "UIView+WebCache.h"
@implementation UIImageView (WebCache) @implementation UIImageView (WebCache)
@ -64,4 +65,14 @@
}]; }];
} }
#pragma mark - State
- (NSURL *)sd_currentImageURL {
return [self sd_imageLoadStateForKey:nil].url;
}
- (void)sd_cancelCurrentImageLoad {
return [self sd_cancelImageLoadOperationWithKey:nil];
}
@end @end

View File

@ -11,6 +11,8 @@
#import "SDWebImageManager.h" #import "SDWebImageManager.h"
#import "SDWebImageTransition.h" #import "SDWebImageTransition.h"
#import "SDWebImageIndicator.h" #import "SDWebImageIndicator.h"
#import "UIView+WebCacheOperation.h"
#import "UIView+WebCacheState.h"
/** /**
The value specify that the image progress unit count cannot be determined because the progressBlock is not been called. The value specify that the image progress unit count cannot be determined because the progressBlock is not been called.
@ -24,27 +26,34 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
*/ */
@interface UIView (WebCache) @interface UIView (WebCache)
/**
* Get the current image URL.
*
* @note Note that because of the limitations of categories this property can get out of sync if you use setImage: directly.
*/
@property (nonatomic, strong, readonly, nullable) NSURL *sd_imageURL;
/** /**
* Get the current image operation key. Operation key is used to identify the different queries for one view instance (like UIButton). * Get the current image operation key. Operation key is used to identify the different queries for one view instance (like UIButton).
* See more about this in `SDWebImageContextSetImageOperationKey`. * See more about this in `SDWebImageContextSetImageOperationKey`.
* If you cancel current image load, the key will be set to nil. *
* @note You can use method `UIView+WebCacheOperation` to investigate different queries' operation. * @note You can use method `UIView+WebCacheOperation` to investigate different queries' operation.
* @note For the history version compatible, when current UIView has property exactly called `image`, the operation key will use `NSStringFromClass(self.class)`. Include `UIImageView.image/NSImageView.image/NSButton.image` (without `UIButton`)
* @warning This property should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), check their header to call correct API, like `UIButton sd_imageURLForState:`
*/ */
@property (nonatomic, strong, readonly, nullable) NSString *sd_latestOperationKey; @property (nonatomic, strong, readonly, nullable) NSString *sd_latestOperationKey;
#pragma mark - State
/**
* Get the current image URL.
* This simply translate to `[self sd_imageLoadStateForKey:self.sd_latestOperationKey].url` from v5.17.0
*
* @note Note that because of the limitations of categories this property can get out of sync if you use setImage: directly.
* @warning This property should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), use `sd_imageLoadStateForKey:` instead. See `UIView+WebCacheState.h` for more information.
*/
@property (nonatomic, strong, readonly, nullable) NSURL *sd_imageURL;
/** /**
* The current image loading progress associated to the view. The unit count is the received size and excepted size of download. * The current image loading progress associated to the view. The unit count is the received size and excepted size of download.
* The `totalUnitCount` and `completedUnitCount` will be reset to 0 after a new image loading start (change from current queue). And they will be set to `SDWebImageProgressUnitCountUnknown` if the progressBlock not been called but the image loading success to mark the progress finished (change from main queue). * The `totalUnitCount` and `completedUnitCount` will be reset to 0 after a new image loading start (change from current queue). And they will be set to `SDWebImageProgressUnitCountUnknown` if the progressBlock not been called but the image loading success to mark the progress finished (change from main queue).
* @note You can use Key-Value Observing on the progress, but you should take care that the change to progress is from a background queue during download(the same as progressBlock). If you want to using KVO and update the UI, make sure to dispatch on the main queue. And it's recommend to use some KVO libs like KVOController because it's more safe and easy to use. * @note You can use Key-Value Observing on the progress, but you should take care that the change to progress is from a background queue during download(the same as progressBlock). If you want to using KVO and update the UI, make sure to dispatch on the main queue. And it's recommend to use some KVO libs like KVOController because it's more safe and easy to use.
* @note The getter will create a progress instance if the value is nil. But by default, we don't create one. If you need to use Key-Value Observing, you must trigger the getter or set a custom progress instance before the loading start. The default value is nil. * @note The getter will create a progress instance if the value is nil. But by default, we don't create one. If you need to use Key-Value Observing, you must trigger the getter or set a custom progress instance before the loading start. The default value is nil.
* @note Note that because of the limitations of categories this property can get out of sync if you update the progress directly. * @note Note that because of the limitations of categories this property can get out of sync if you update the progress directly.
* @warning This property should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), use `sd_imageLoadStateForKey:` instead. See `UIView+WebCacheState.h` for more information.
*/ */
@property (nonatomic, strong, null_resettable) NSProgress *sd_imageProgress; @property (nonatomic, strong, null_resettable) NSProgress *sd_imageProgress;
@ -83,6 +92,9 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
/** /**
* Cancel the current image load * Cancel the current image load
* This simply translate to `[self sd_cancelImageLoadOperationWithKey:self.sd_latestOperationKey]` from v5.17.0
*
* @warning This method should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), use `sd_cancelImageLoadOperationWithKey:` instead. See `UIView+WebCacheOperation.h` for more information.
*/ */
- (void)sd_cancelCurrentImageLoad; - (void)sd_cancelCurrentImageLoad;
@ -93,6 +105,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
/** /**
The image transition when image load finished. See `SDWebImageTransition`. The image transition when image load finished. See `SDWebImageTransition`.
If you specify nil, do not do transition. Defaults to nil. If you specify nil, do not do transition. Defaults to nil.
@warning This property should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), write your own implementation in `setImageBlock:`, and check current stateful view's state to render the UI.
*/ */
@property (nonatomic, strong, nullable) SDWebImageTransition *sd_imageTransition; @property (nonatomic, strong, nullable) SDWebImageTransition *sd_imageTransition;
@ -102,6 +115,7 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
The image indicator during the image loading. If you do not need indicator, specify nil. Defaults to nil The image indicator during the image loading. If you do not need indicator, specify nil. Defaults to nil
The setter will remove the old indicator view and add new indicator view to current view's subview. The setter will remove the old indicator view and add new indicator view to current view's subview.
@note Because this is UI related, you should access only from the main queue. @note Because this is UI related, you should access only from the main queue.
@warning This property should be only used for single state view, like `UIImageView` without highlighted state. For stateful view like `UIBUtton` (one view can have multiple images loading), write your own implementation in `setImageBlock:`, and check current stateful view's state to render the UI.
*/ */
@property (nonatomic, strong, nullable) id<SDWebImageIndicator> sd_imageIndicator; @property (nonatomic, strong, nullable) id<SDWebImageIndicator> sd_imageIndicator;

View File

@ -18,14 +18,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
@implementation UIView (WebCache) @implementation UIView (WebCache)
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, @selector(sd_imageURL));
}
- (void)setSd_imageURL:(NSURL * _Nullable)sd_imageURL {
objc_setAssociatedObject(self, @selector(sd_imageURL), sd_imageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (nullable NSString *)sd_latestOperationKey { - (nullable NSString *)sd_latestOperationKey {
return objc_getAssociatedObject(self, @selector(sd_latestOperationKey)); return objc_getAssociatedObject(self, @selector(sd_latestOperationKey));
} }
@ -34,8 +26,15 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
objc_setAssociatedObject(self, @selector(sd_latestOperationKey), sd_latestOperationKey, OBJC_ASSOCIATION_COPY_NONATOMIC); objc_setAssociatedObject(self, @selector(sd_latestOperationKey), sd_latestOperationKey, OBJC_ASSOCIATION_COPY_NONATOMIC);
} }
#pragma mark - State
- (NSURL *)sd_imageURL {
return [self sd_imageLoadStateForKey:self.sd_latestOperationKey].url;
}
- (NSProgress *)sd_imageProgress { - (NSProgress *)sd_imageProgress {
NSProgress *progress = objc_getAssociatedObject(self, @selector(sd_imageProgress)); SDWebImageLoadState *loadState = [self sd_imageLoadStateForKey:self.sd_latestOperationKey];
NSProgress *progress = loadState.progress;
if (!progress) { if (!progress) {
progress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; progress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.sd_imageProgress = progress; self.sd_imageProgress = progress;
@ -44,7 +43,15 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
} }
- (void)setSd_imageProgress:(NSProgress *)sd_imageProgress { - (void)setSd_imageProgress:(NSProgress *)sd_imageProgress {
objc_setAssociatedObject(self, @selector(sd_imageProgress), sd_imageProgress, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (!sd_imageProgress) {
return;
}
SDWebImageLoadState *loadState = [self sd_imageLoadStateForKey:self.sd_latestOperationKey];
if (!loadState) {
loadState = [SDWebImageLoadState new];
}
loadState.progress = sd_imageProgress;
[self sd_setImageLoadState:loadState forKey:self.sd_latestOperationKey];
} }
- (nullable id<SDWebImageOperation>)sd_internalSetImageWithURL:(nullable NSURL *)url - (nullable id<SDWebImageOperation>)sd_internalSetImageWithURL:(nullable NSURL *)url
@ -70,7 +77,12 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
} }
self.sd_latestOperationKey = validOperationKey; self.sd_latestOperationKey = validOperationKey;
[self sd_cancelImageLoadOperationWithKey:validOperationKey]; [self sd_cancelImageLoadOperationWithKey:validOperationKey];
self.sd_imageURL = url; SDWebImageLoadState *loadState = [self sd_imageLoadStateForKey:validOperationKey];
if (!loadState) {
loadState = [SDWebImageLoadState new];
}
loadState.url = url;
[self sd_setImageLoadState:loadState forKey:validOperationKey];
SDWebImageManager *manager = context[SDWebImageContextCustomManager]; SDWebImageManager *manager = context[SDWebImageContextCustomManager];
if (!manager) { if (!manager) {
@ -103,7 +115,7 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
if (url) { if (url) {
// reset the progress // reset the progress
NSProgress *imageProgress = objc_getAssociatedObject(self, @selector(sd_imageProgress)); NSProgress *imageProgress = loadState.progress;
if (imageProgress) { if (imageProgress) {
imageProgress.totalUnitCount = 0; imageProgress.totalUnitCount = 0;
imageProgress.completedUnitCount = 0; imageProgress.completedUnitCount = 0;
@ -242,7 +254,6 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
- (void)sd_cancelCurrentImageLoad { - (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:self.sd_latestOperationKey]; [self sd_cancelImageLoadOperationWithKey:self.sd_latestOperationKey];
self.sd_latestOperationKey = nil;
} }
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL {

View File

@ -0,0 +1,62 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
/**
A loading state to manage View Category which contains multiple states. Like UIImgeView.image && UIImageView.highlightedImage
@code
SDWebImageLoadState *loadState = [self sd_imageLoadStateForKey:@keypath(self, highlitedImage)];
NSProgress *highlitedImageProgress = loadState.progress;
@endcode
*/
@interface SDWebImageLoadState : NSObject
/**
Image loading URL
*/
@property (nonatomic, strong, nullable) NSURL *url;
/**
Image loading progress. The unit count is the received size and excepted size of download.
*/
@property (nonatomic, strong, nullable) NSProgress *progress;
@end
/**
These methods are used for WebCache view which have multiple states for image loading, for example, `UIButton` or `UIImageView.highlightedImage`
It maitain the state container for per-operation, make it possible for control and check each image loading operation's state.
@note For developer who want to add SDWebImage View Category support for their own stateful class, learn more on Wiki.
*/
@interface UIView (WebCacheState)
/**
Get the image loading state container for specify operation key
@param key key for identifying the operations
@return The image loading state container
*/
- (nullable SDWebImageLoadState *)sd_imageLoadStateForKey:(nullable NSString *)key;
/**
Set the image loading state container for specify operation key
@param state The image loading state container
@param key key for identifying the operations
*/
- (void)sd_setImageLoadState:(nullable SDWebImageLoadState *)state forKey:(nullable NSString *)key;
/**
Rmove the image loading state container for specify operation key
@param key key for identifying the operations
*/
- (void)sd_removeImageLoadStateForKey:(nullable NSString *)key;
@end

View File

@ -0,0 +1,57 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "UIView+WebCacheState.h"
#import "objc/runtime.h"
static char loadStateKey;
typedef NSMutableDictionary<NSString *, SDWebImageLoadState *> SDStatesDictionary;
@implementation SDWebImageLoadState
@end
@implementation UIView (WebCacheState)
- (SDStatesDictionary *)sd_imageLoadStateDictionary {
SDStatesDictionary *states = objc_getAssociatedObject(self, &loadStateKey);
if (!states) {
states = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &loadStateKey, states, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return states;
}
- (SDWebImageLoadState *)sd_imageLoadStateForKey:(NSString *)key {
if (!key) {
key = NSStringFromClass(self.class);
}
@synchronized(self) {
return [self.sd_imageLoadStateDictionary objectForKey:key];
}
}
- (void)sd_setImageLoadState:(SDWebImageLoadState *)state forKey:(NSString *)key {
if (!key) {
key = NSStringFromClass(self.class);
}
@synchronized(self) {
self.sd_imageLoadStateDictionary[key] = state;
}
}
- (void)sd_removeImageLoadStateForKey:(NSString *)key {
if (!key) {
key = NSStringFromClass(self.class);
}
@synchronized(self) {
self.sd_imageLoadStateDictionary[key] = nil;
}
}
@end

View File

@ -120,3 +120,68 @@ extern "C" {
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
/**
* \@keypath allows compile-time verification of key paths. Given a real object
* receiver and key path:
*
* @code
NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String);
// => @"lowercaseString.UTF8String"
NSString *versionPath = @keypath(NSObject, version);
// => @"version"
NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString);
// => @"lowercaseString"
* @endcode
*
* ... the macro returns an \c NSString containing all but the first path
* component or argument (e.g., @"lowercaseString.UTF8String", @"version").
*
* In addition to simply creating a key path, this macro ensures that the key
* path is valid at compile-time (causing a syntax error if not), and supports
* refactoring, such that changing the name of the property will also update any
* uses of \@keypath.
*/
#define keypath(...) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-repeated-use-of-weak\"") \
(NO).boolValue ? ((NSString * _Nonnull)nil) : ((NSString * _Nonnull)@(cStringKeypath(__VA_ARGS__))) \
_Pragma("clang diagnostic pop") \
#define cStringKeypath(...) \
metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))
#define keypath1(PATH) \
(((void)(NO && ((void)PATH, NO)), \
({ char *__extobjckeypath__ = strchr(# PATH, '.'); NSCAssert(__extobjckeypath__, @"Provided key path is invalid."); __extobjckeypath__ + 1; })))
#define keypath2(OBJ, PATH) \
(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))
/**
* \@collectionKeypath allows compile-time verification of key paths across collections NSArray/NSSet etc. Given a real object
* receiver, collection object receiver and related keypaths:
*
* @code
NSString *employeesFirstNamePath = @collectionKeypath(department.employees, Employee.new, firstName)
// => @"employees.firstName"
NSString *employeesFirstNamePath = @collectionKeypath(Department.new, employees, Employee.new, firstName)
// => @"employees.firstName"
* @endcode
*
*/
#define collectionKeypath(...) \
metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__))(collectionKeypath3(__VA_ARGS__))(collectionKeypath4(__VA_ARGS__))
#define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) \
(YES).boolValue ? (NSString * _Nonnull)@((const char * _Nonnull)[[NSString stringWithFormat:@"%s.%s", cStringKeypath(PATH), cStringKeypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) : (NSString * _Nonnull)nil
#define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) \
(YES).boolValue ? (NSString * _Nonnull)@((const char * _Nonnull)[[NSString stringWithFormat:@"%s.%s", cStringKeypath(OBJ, PATH), cStringKeypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) : (NSString * _Nonnull)nil

View File

@ -0,0 +1 @@
../../Core/UIView+WebCacheState.h

View File

@ -314,7 +314,6 @@
[imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil]; [imageView sd_internalSetImageWithURL:originalImageURL placeholderImage:nil options:0 context:nil setImageBlock:nil progress:nil completed:nil];
[imageView sd_cancelCurrentImageLoad]; [imageView sd_cancelCurrentImageLoad];
NSString *operationKey = NSStringFromClass(UIView.class); NSString *operationKey = NSStringFromClass(UIView.class);
expect(imageView.sd_latestOperationKey).beNil();
expect([imageView sd_imageLoadOperationForKey:operationKey]).beNil(); expect([imageView sd_imageLoadOperationForKey:operationKey]).beNil();
} }

View File

@ -40,6 +40,7 @@ FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[];
#import <SDWebImage/UIButton+WebCache.h> #import <SDWebImage/UIButton+WebCache.h>
#import <SDWebImage/SDWebImagePrefetcher.h> #import <SDWebImage/SDWebImagePrefetcher.h>
#import <SDWebImage/UIView+WebCacheOperation.h> #import <SDWebImage/UIView+WebCacheOperation.h>
#import <SDWebImage/UIView+WebCacheState.h>
#import <SDWebImage/UIImage+Metadata.h> #import <SDWebImage/UIImage+Metadata.h>
#import <SDWebImage/UIImage+MultiFormat.h> #import <SDWebImage/UIImage+MultiFormat.h>
#import <SDWebImage/UIImage+MemoryCacheCost.h> #import <SDWebImage/UIImage+MemoryCacheCost.h>