Refactored all the duplicate code from our WebCache categories into a UIView+WebCache category. All the other categories will make calls to this one. Customization of setting the image is done via the setImageBlock and the operationKey

This commit is contained in:
Bogdan Poplauschi 2016-09-25 19:44:52 +03:00
parent 7d02ffd6ab
commit e1840c3262
14 changed files with 396 additions and 437 deletions

View File

@ -11,6 +11,7 @@
#import "DetailViewController.h"
#import <SDWebImage/FLAnimatedImageView.h>
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
#import <SDWebImage/UIView+WebCache.h>
@interface MyCustomTableViewCell : UITableViewCell

View File

@ -297,6 +297,18 @@
431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; };
431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D8B148C56230056699D /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; };
431BB6FC1D06D2C1006A3455 /* SDWebImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D89148C56230056699D /* SDWebImageDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4369C2751D9807EC007E863A /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2761D9807EC007E863A /* UIView+WebCache.m */; };
438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
438096731CDFC08F00DC626B /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; };
438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -891,6 +903,8 @@
00733A4C1BC487C000A5A117 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4314D1991D0E0E3B004B36C9 /* libSDWebImage watchOS static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDWebImage watchOS static.a"; sourceTree = BUILT_PRODUCTS_DIR; };
431BB7031D06D2C1006A3455 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4369C2751D9807EC007E863A /* UIView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = "<group>"; };
4369C2761D9807EC007E863A /* UIView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = "<group>"; };
4397D2F21D0DDD8C00BB2784 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+WebCache.h"; path = "SDWebImage/NSImage+WebCache.h"; sourceTree = "<group>"; };
4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSImage+WebCache.m"; path = "SDWebImage/NSImage+WebCache.m"; sourceTree = "<group>"; };
@ -1116,6 +1130,8 @@
ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */,
53922D95148C56230056699D /* UIImageView+WebCache.h */,
53922D96148C56230056699D /* UIImageView+WebCache.m */,
4369C2751D9807EC007E863A /* UIView+WebCache.h */,
4369C2761D9807EC007E863A /* UIView+WebCache.m */,
);
name = "WebCache Categories";
path = ..;
@ -1438,6 +1454,7 @@
431739561CDFC8B70008FEB9 /* demux.h in Headers */,
4317394D1CDFC8B20008FEB9 /* utils.h in Headers */,
4397D2F81D0DF44200BB2784 /* MKAnnotationView+WebCache.h in Headers */,
4369C27A1D9807EC007E863A /* UIView+WebCache.h in Headers */,
431739451CDFC8B20008FEB9 /* quant_levels_dec.h in Headers */,
431739361CDFC8B20008FEB9 /* bit_reader_inl.h in Headers */,
4317393A1CDFC8B20008FEB9 /* color_cache.h in Headers */,
@ -1524,6 +1541,7 @@
4314D17B1D0E0E3B004B36C9 /* huffman_encode.h in Headers */,
43DA7CD91D10865E0028BE58 /* dsp.h in Headers */,
4314D17C1D0E0E3B004B36C9 /* UIImage+WebP.h in Headers */,
4369C2781D9807EC007E863A /* UIView+WebCache.h in Headers */,
4314D17D1D0E0E3B004B36C9 /* SDWebImagePrefetcher.h in Headers */,
4314D17E1D0E0E3B004B36C9 /* bit_writer.h in Headers */,
43DA7CF01D10865E0028BE58 /* neon.h in Headers */,
@ -1585,6 +1603,7 @@
43DA7D931D1086600028BE58 /* lossless.h in Headers */,
431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */,
431BB6EF1D06D2C1006A3455 /* SDWebImagePrefetcher.h in Headers */,
4369C27B1D9807EC007E863A /* UIView+WebCache.h in Headers */,
431BB6F01D06D2C1006A3455 /* SDWebImageOperation.h in Headers */,
43A62A201D0E0A800089D7DD /* mux_types.h in Headers */,
43A62A2F1D0E0A860089D7DD /* huffman_encode.h in Headers */,
@ -1621,6 +1640,7 @@
4397D2C31D0DDD8C00BB2784 /* SDWebImageManager.h in Headers */,
4397D2C41D0DDD8C00BB2784 /* SDImageCache.h in Headers */,
4397D2C51D0DDD8C00BB2784 /* UIImageView+WebCache.h in Headers */,
4369C27C1D9807EC007E863A /* UIView+WebCache.h in Headers */,
4397D2C61D0DDD8C00BB2784 /* random.h in Headers */,
4397D2C71D0DDD8C00BB2784 /* rescaler.h in Headers */,
43DA7DE11D10867D0028BE58 /* extras.h in Headers */,
@ -1675,6 +1695,7 @@
431739211CDFC8B20008FEB9 /* endian_inl.h in Headers */,
43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */,
431739541CDFC8B70008FEB9 /* types.h in Headers */,
4369C2791D9807EC007E863A /* UIView+WebCache.h in Headers */,
431738C51CDFC8A30008FEB9 /* alphai.h in Headers */,
4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */,
431739511CDFC8B70008FEB9 /* format_constants.h in Headers */,
@ -1758,6 +1779,7 @@
431738BD1CDFC2660008FEB9 /* decode.h in Headers */,
53761319155AD0D5005750A4 /* SDWebImageDecoder.h in Headers */,
5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */,
4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */,
5376131C155AD0D5005750A4 /* SDWebImageManager.h in Headers */,
431738B01CDFC2630008FEB9 /* huffman_encode.h in Headers */,
438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */,
@ -2092,6 +2114,7 @@
43DA7D681D1086600028BE58 /* yuv_mips_dsp_r2.c in Sources */,
43DA7D651D1086600028BE58 /* upsampling_neon.c in Sources */,
43DA7D371D1086600028BE58 /* alpha_processing.c in Sources */,
4369C2811D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7D691D1086600028BE58 /* yuv_mips32.c in Sources */,
43DA7D5F1D1086600028BE58 /* rescaler_mips_dsp_r2.c in Sources */,
00733A5E1BC4880000A5A117 /* UIImage+MultiFormat.m in Sources */,
@ -2123,6 +2146,7 @@
43DA7CDB1D10865E0028BE58 /* enc_mips_dsp_r2.c in Sources */,
4314D12F1D0E0E3B004B36C9 /* thread.c in Sources */,
4314D1311D0E0E3B004B36C9 /* SDWebImageDownloader.m in Sources */,
4369C27F1D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7CC91D10865E0028BE58 /* alpha_processing.c in Sources */,
4314D1321D0E0E3B004B36C9 /* filters.c in Sources */,
4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */,
@ -2220,6 +2244,7 @@
43DA7D801D1086600028BE58 /* enc_mips_dsp_r2.c in Sources */,
43A62A631D0E0A8F0089D7DD /* vp8l.c in Sources */,
431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */,
4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7D6E1D1086600028BE58 /* alpha_processing.c in Sources */,
43A62A5E1D0E0A8F0089D7DD /* io.c in Sources */,
43A62A321D0E0A860089D7DD /* quant_levels_dec.c in Sources */,
@ -2375,6 +2400,7 @@
43DA7DB01D1086610028BE58 /* dec_mips32.c in Sources */,
43DA7DAA1D1086610028BE58 /* cost_mips32.c in Sources */,
43DA7DAB1D1086610028BE58 /* cost_sse2.c in Sources */,
4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7DB71D1086610028BE58 /* enc_mips_dsp_r2.c in Sources */,
43DA7DC11D1086610028BE58 /* lossless_enc_mips32.c in Sources */,
43DA7DBC1D1086610028BE58 /* enc.c in Sources */,
@ -2486,6 +2512,7 @@
43DA7D311D10865F0028BE58 /* yuv_mips_dsp_r2.c in Sources */,
43DA7D2E1D10865F0028BE58 /* upsampling_neon.c in Sources */,
43DA7D001D10865F0028BE58 /* alpha_processing.c in Sources */,
4369C2801D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7D321D10865F0028BE58 /* yuv_mips32.c in Sources */,
43DA7D281D10865F0028BE58 /* rescaler_mips_dsp_r2.c in Sources */,
431738C81CDFC8A30008FEB9 /* frame.c in Sources */,
@ -2587,6 +2614,7 @@
43DA7CC31D1086570028BE58 /* yuv_mips_dsp_r2.c in Sources */,
43DA7CC01D1086570028BE58 /* upsampling_neon.c in Sources */,
43DA7C921D1086570028BE58 /* alpha_processing.c in Sources */,
4369C27E1D9807EC007E863A /* UIView+WebCache.m in Sources */,
43DA7CC41D1086570028BE58 /* yuv_mips32.c in Sources */,
43DA7CBA1D1086570028BE58 /* rescaler_mips_dsp_r2.c in Sources */,
4317387C1CDFC2580008FEB9 /* frame.c in Sources */,

View File

@ -11,9 +11,9 @@
#if SD_UIKIT
#if COCOAPODS
@import FLAnimatedImage;
@import FLAnimatedImage;
#else
#import "FLAnimatedImageView.h"
#import "FLAnimatedImageView.h"
#endif
#import "SDWebImageManager.h"
@ -25,14 +25,6 @@
*/
@interface FLAnimatedImageView (WebCache)
/**
* Get the current image URL.
*
* Note that because of the limitations of categories this property can get out of sync
* if you use setImage: directly.
*/
- (nullable NSURL *)sd_imageURL;
/**
* Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images
* The download is asynchronous and cached.
@ -136,11 +128,6 @@
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the image load
*/
- (void)sd_cancelCurrentImageLoad;
@end
#endif

View File

@ -11,19 +11,13 @@
#import "FLAnimatedImageView+WebCache.h"
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
#import "UIView+WebCache.h"
#import "NSData+ImageContentType.h"
#import "FLAnimatedImage.h"
#import "UIImageView+WebCache.h"
static char imageURLKey;
@implementation FLAnimatedImageView (WebCache)
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, &imageURLKey);
}
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
@ -53,70 +47,25 @@ static char imageURLKey;
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_cancelCurrentImageLoad];
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
self.image = placeholder;
});
}
if (url) {
// check if activityView is enabled or not
if ([self showActivityIndicatorView]) {
[self addActivityIndicator];
}
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_sync_safe(^{
[wself removeActivityIndicator];
if (!wself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
completedBlock(image, error, cacheType, url);
return;
} else if (image) {
SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
if (imageFormat == SDImageFormatGIF) {
wself.animatedImage = [FLAnimatedImage animatedImageWithGIFData:data];
wself.image = nil;
} else {
wself.image = image;
wself.animatedImage = nil;
}
[wself setNeedsLayout];
} else {
if ((options & SDWebImageDelayPlaceholder)) {
wself.image = placeholder;
[wself setNeedsLayout];
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
} else {
dispatch_main_async_safe(^{
[self removeActivityIndicator];
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:nil
setImageBlock:^(UIImage *image, NSData *imageData) {
SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
if (imageFormat == SDImageFormatGIF) {
weakSelf.animatedImage = [FLAnimatedImage animatedImageWithGIFData:data];
weakSelf.image = nil;
} else {
weakSelf.image = image;
weakSelf.animatedImage = nil;
}
}
progress:progressBlock
completed:completedBlock];
}
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];
}
@end
#endif

View File

@ -18,14 +18,6 @@
*/
@interface MKAnnotationView (WebCache)
/**
* Get the current image URL.
*
* Note that because of the limitations of categories this property can get out of sync
* if you use setImage: directly.
*/
- (nullable NSURL *)sd_imageURL;
/**
* Set the imageView `image` with an `url`.
*
@ -112,11 +104,6 @@
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the current download
*/
- (void)sd_cancelCurrentImageLoad;
@end
#endif

View File

@ -12,15 +12,10 @@
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
static char imageURLKey;
#import "UIView+WebCache.h"
@implementation MKAnnotationView (WebCache)
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, &imageURLKey);
}
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil];
}
@ -45,56 +40,16 @@ static char imageURLKey;
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_cancelCurrentImageLoad];
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.image = placeholder;
if (url) {
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_sync_safe(^{
__strong MKAnnotationView *sself = wself;
if (!sself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
completedBlock(image, error, cacheType, url);
return;
} else if (image) {
wself.image = image;
#if SD_UIKIT
[wself setNeedsLayout];
#elif SD_MAC
[wself setNeedsLayout:YES];
#endif
} else {
if ((options & SDWebImageDelayPlaceholder)) {
wself.image = placeholder;
#if SD_UIKIT
[wself setNeedsLayout];
#elif SD_MAC
[wself setNeedsDisplay:YES];
#endif
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forKey:@"MKAnnotationViewImage"];
} else {
dispatch_main_async_safe(^{
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
if (completedBlock) {
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
}
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:@"MKAnnotationViewImage"];
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:nil
setImageBlock:^(UIImage *image, NSData *imageData) {
weakSelf.image = image;
}
progress:nil
completed:completedBlock];
}
@end

View File

@ -22,6 +22,8 @@
*/
- (nullable NSURL *)sd_currentImageURL;
#pragma mark - Image
/**
* Get the image URL for a control state.
*
@ -126,6 +128,8 @@
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
#pragma mark - Background image
/**
* Set the backgroundImageView `image` with an `url`.
*
@ -222,6 +226,8 @@
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
#pragma mark - Cancel
/**
* Cancel the current image download
*/

View File

@ -12,6 +12,7 @@
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
#import "UIView+WebCache.h"
static char imageURLStorageKey;
@ -33,6 +34,8 @@ typedef NSMutableDictionary<NSNumber *, NSURL *> SDStateImageURLDictionary;
return self.imageURLStorage[@(state)];
}
#pragma mark - Image
- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
[self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
}
@ -58,46 +61,27 @@ typedef NSMutableDictionary<NSNumber *, NSURL *> SDStateImageURLDictionary;
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self setImage:placeholder forState:state];
[self sd_cancelImageLoadForState:state];
if (!url) {
[self.imageURLStorage removeObjectForKey:@(state)];
dispatch_main_async_safe(^{
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
return;
}
self.imageURLStorage[@(state)] = url;
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_sync_safe(^{
__strong UIButton *sself = wself;
if (!sself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
{
completedBlock(image, error, cacheType, url);
return;
}
else if (image) {
[sself setImage:image forState:state];
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forState:state];
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]
setImageBlock:^(UIImage *image, NSData *imageData) {
[weakSelf setImage:image forState:state];
}
progress:nil
completed:completedBlock];
}
#pragma mark - Background image
- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
[self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
}
@ -123,39 +107,23 @@ typedef NSMutableDictionary<NSNumber *, NSURL *> SDStateImageURLDictionary;
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_cancelBackgroundImageLoadForState:state];
[self setBackgroundImage:placeholder forState:state];
if (url) {
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_sync_safe(^{
__strong UIButton *sself = wself;
if (!sself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
{
completedBlock(image, error, cacheType, url);
return;
}
else if (image) {
[sself setBackgroundImage:image forState:state];
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setBackgroundImageLoadOperation:operation forState:state];
} else {
dispatch_main_async_safe(^{
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
if (completedBlock) {
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
if (!url) {
[self.imageURLStorage removeObjectForKey:@(state)];
return;
}
self.imageURLStorage[@(state)] = url;
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]
setImageBlock:^(UIImage *image, NSData *imageData) {
[weakSelf setBackgroundImage:image forState:state];
}
progress:nil
completed:completedBlock];
}
- (void)sd_setImageLoadOperation:(id<SDWebImageOperation>)operation forState:(UIControlState)state {
@ -176,8 +144,7 @@ typedef NSMutableDictionary<NSNumber *, NSURL *> SDStateImageURLDictionary;
- (SDStateImageURLDictionary *)imageURLStorage {
SDStateImageURLDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey);
if (!storage)
{
if (!storage) {
storage = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &imageURLStorageKey, storage, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

View File

@ -88,11 +88,6 @@
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the current download
*/
- (void)sd_cancelCurrentHighlightedImageLoad;
@end
#endif

View File

@ -11,8 +11,7 @@
#if SD_UIKIT
#import "UIView+WebCacheOperation.h"
#define UIImageViewHighlightedWebCacheOperationKey @"highlightedImage"
#import "UIView+WebCache.h"
@implementation UIImageView (HighlightedWebCache)
@ -36,41 +35,16 @@
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_cancelCurrentHighlightedImageLoad];
if (url) {
__weak __typeof(self)wself = self;
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!wself) return;
dispatch_main_sync_safe (^{
if (!wself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
{
completedBlock(image, error, cacheType, url);
return;
}
else if (image) {
wself.highlightedImage = image;
[wself setNeedsLayout];
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forKey:UIImageViewHighlightedWebCacheOperationKey];
} else {
dispatch_main_async_safe(^{
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
if (completedBlock) {
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
}
- (void)sd_cancelCurrentHighlightedImageLoad {
[self sd_cancelImageLoadOperationWithKey:UIImageViewHighlightedWebCacheOperationKey];
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:nil
options:options
operationKey:@"UIImageViewImageOperationHighlighted"
setImageBlock:^(UIImage *image, NSData *imageData) {
weakSelf.highlightedImage = image;
}
progress:progressBlock
completed:completedBlock];
}
@end

View File

@ -47,14 +47,6 @@
*/
@interface UIImageView (WebCache)
/**
* Get the current image URL.
*
* Note that because of the limitations of categories this property can get out of sync
* if you use setImage: directly.
*/
- (nullable NSURL *)sd_imageURL;
/**
* Set the imageView `image` with an `url`.
*
@ -183,37 +175,18 @@
completed:(nullable SDExternalCompletionBlock)completedBlock;
#if SD_UIKIT
#pragma mark - Animation of multiple images
/**
* Download an array of images and starts them in an animation loop
*
* @param arrayOfURLs An array of NSURL
*/
- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs;
#endif
/**
* Cancel the current download
*/
- (void)sd_cancelCurrentImageLoad;
#if SD_UIKIT
- (void)sd_cancelCurrentAnimationImagesLoad;
/**
* Show activity UIActivityIndicatorView
*/
- (void)setShowActivityIndicatorView:(BOOL)show;
/**
* set desired UIActivityIndicatorViewStyle
*
* @param style The style of the UIActivityIndicatorView
*/
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style;
- (BOOL)showActivityIndicatorView;
- (void)addActivityIndicator;
- (void)removeActivityIndicator;
#endif
@end

View File

@ -12,13 +12,7 @@
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
static char imageURLKey;
#if SD_UIKIT
static char TAG_ACTIVITY_INDICATOR;
static char TAG_ACTIVITY_STYLE;
#endif
static char TAG_ACTIVITY_SHOW;
#import "UIView+WebCache.h"
@implementation UIImageView (WebCache)
@ -51,65 +45,13 @@ static char TAG_ACTIVITY_SHOW;
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_cancelCurrentImageLoad];
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
self.image = placeholder;
});
}
if (url) {
// check if activityView is enabled or not
if ([self showActivityIndicatorView]) {
[self addActivityIndicator];
}
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
[wself removeActivityIndicator];
if (!wself) return;
dispatch_main_sync_safe(^{
if (!wself) return;
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
{
completedBlock(image, error, cacheType, url);
return;
}
else if (image) {
wself.image = image;
#if SD_UIKIT
[wself setNeedsLayout];
#elif SD_MAC
[wself setNeedsLayout:YES];
#endif
} else {
if ((options & SDWebImageDelayPlaceholder)) {
wself.image = placeholder;
#if SD_UIKIT
[wself setNeedsLayout];
#elif SD_MAC
[wself setNeedsLayout:YES];
#endif
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
} else {
dispatch_main_async_safe(^{
[self removeActivityIndicator];
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:nil
setImageBlock:nil
progress:progressBlock
completed:completedBlock];
}
- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url
@ -123,11 +65,10 @@ static char TAG_ACTIVITY_SHOW;
[self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock];
}
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, &imageURLKey);
}
#if SD_UIKIT
#pragma mark - Animation of multiple images
- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs {
[self sd_cancelCurrentAnimationImagesLoad];
__weak __typeof(self)wself = self;
@ -158,88 +99,12 @@ static char TAG_ACTIVITY_SHOW;
[self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"];
}
#endif
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];
}
#if SD_UIKIT
- (void)sd_cancelCurrentAnimationImagesLoad {
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"];
}
#endif
#pragma mark -
#if SD_UIKIT
- (UIActivityIndicatorView *)activityIndicator {
return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR);
}
- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator {
objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN);
}
#endif
- (void)setShowActivityIndicatorView:(BOOL)show {
objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN);
}
- (BOOL)showActivityIndicatorView {
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue];
}
#if SD_UIKIT
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style{
objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN);
}
- (int)getIndicatorStyle{
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue];
}
#endif
- (void)addActivityIndicator {
#if SD_UIKIT
if (!self.activityIndicator) {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self getIndicatorStyle]];
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
dispatch_main_async_safe(^{
[self addSubview:self.activityIndicator];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
});
}
dispatch_main_async_safe(^{
[self.activityIndicator startAnimating];
});
#endif
}
- (void)removeActivityIndicator {
#if SD_UIKIT
if (self.activityIndicator) {
[self.activityIndicator removeFromSuperview];
self.activityIndicator = nil;
}
#endif
}
@end
#endif

View File

@ -0,0 +1,81 @@
/*
* 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 "SDWebImageCompat.h"
#if SD_UIKIT || SD_MAC
#import "SDWebImageManager.h"
typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData);
@interface UIView (WebCache)
/**
* Get the current image URL.
*
* Note that because of the limitations of categories this property can get out of sync
* if you use setImage: directly.
*/
- (nullable NSURL *)sd_imageURL;
/**
* Set the imageView `image` with an `url` and optionally a placeholder image.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
* @param operationKey A string to be used as the operation key. If nil, will use the class name
* @param setImageBlock Block used for custom set image code
* @param progressBlock A block called while image is downloading
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
operationKey:(nullable NSString *)operationKey
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Cancel the current download
*/
- (void)sd_cancelCurrentImageLoad;
#if SD_UIKIT
#pragma mark - Activity indicator
/**
* Show activity UIActivityIndicatorView
*/
- (void)setShowActivityIndicatorView:(BOOL)show;
/**
* set desired UIActivityIndicatorViewStyle
*
* @param style The style of the UIActivityIndicatorView
*/
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style;
- (BOOL)showActivityIndicatorView;
- (void)addActivityIndicator;
- (void)removeActivityIndicator;
#endif
@end
#endif

View File

@ -0,0 +1,191 @@
/*
* 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+WebCache.h"
#if SD_UIKIT || SD_MAC
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
static char imageURLKey;
#if SD_UIKIT
static char TAG_ACTIVITY_INDICATOR;
static char TAG_ACTIVITY_STYLE;
#endif
static char TAG_ACTIVITY_SHOW;
@implementation UIView (WebCache)
- (nullable NSURL *)sd_imageURL {
return objc_getAssociatedObject(self, &imageURLKey);
}
- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
operationKey:(nullable NSString *)operationKey
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
});
}
if (url) {
// check if activityView is enabled or not
if ([self showActivityIndicatorView]) {
[self addActivityIndicator];
}
__weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
__strong __typeof (wself) sself = wself;
[sself removeActivityIndicator];
if (!sself) {
return;
}
dispatch_main_sync_safe(^{
if (!sself) {
return;
}
if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
completedBlock(image, error, cacheType, url);
return;
} else if (image) {
[sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setNeedsLayout];
} else {
if ((options & SDWebImageDelayPlaceholder)) {
[sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setNeedsLayout];
}
}
if (completedBlock && finished) {
completedBlock(image, error, cacheType, url);
}
});
}];
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
} else {
dispatch_main_async_safe(^{
[self removeActivityIndicator];
if (completedBlock) {
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
completedBlock(nil, error, SDImageCacheTypeNone, url);
}
});
}
}
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])];
}
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock {
if (setImageBlock) {
setImageBlock(image, imageData);
} else if ([self isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = (UIImageView *)self;
imageView.image = image;
} else if ([self isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)self;
[button setImage:image forState:UIControlStateNormal];
}
}
- (void)sd_setNeedsLayout {
#if SD_UIKIT
[self setNeedsLayout];
#elif SD_MAC
[self setNeedsLayout:YES];
#endif
}
#pragma mark - Activity indicator
#pragma mark -
#if SD_UIKIT
- (UIActivityIndicatorView *)activityIndicator {
return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR);
}
- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator {
objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN);
}
#endif
- (void)setShowActivityIndicatorView:(BOOL)show {
objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN);
}
- (BOOL)showActivityIndicatorView {
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue];
}
#if SD_UIKIT
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style{
objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN);
}
- (int)getIndicatorStyle{
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue];
}
#endif
- (void)addActivityIndicator {
#if SD_UIKIT
if (!self.activityIndicator) {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self getIndicatorStyle]];
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
dispatch_main_async_safe(^{
[self addSubview:self.activityIndicator];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
});
}
dispatch_main_async_safe(^{
[self.activityIndicator startAnimating];
});
#endif
}
- (void)removeActivityIndicator {
#if SD_UIKIT
if (self.activityIndicator) {
[self.activityIndicator removeFromSuperview];
self.activityIndicator = nil;
}
#endif
}
@end
#endif