Merge pull request #1681 from rs/testing
Unit Testing + some refactoring due to testing
This commit is contained in:
commit
375f29d745
|
@ -46,3 +46,6 @@ script:
|
|||
- pod install --project-directory=Tests
|
||||
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
|
||||
- xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' -configuration Debug | xcpretty -c
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
|
@ -11,6 +11,7 @@
|
|||
#import "DetailViewController.h"
|
||||
#import <SDWebImage/FLAnimatedImageView.h>
|
||||
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
|
||||
#import <SDWebImage/UIView+WebCache.h>
|
||||
|
||||
|
||||
@interface MyCustomTableViewCell : UITableViewCell
|
||||
|
@ -71,6 +72,7 @@
|
|||
@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif",
|
||||
@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp",
|
||||
@"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp",
|
||||
@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png",
|
||||
nil];
|
||||
|
||||
for (int i=0; i<100; i++) {
|
||||
|
@ -86,7 +88,7 @@
|
|||
- (void)flushCache
|
||||
{
|
||||
[SDWebImageManager.sharedManager.imageCache clearMemory];
|
||||
[SDWebImageManager.sharedManager.imageCache clearDisk];
|
||||
[SDWebImageManager.sharedManager.imageCache clearDiskOnCompletion:nil];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[![Dependency Status](https://www.versioneye.com/objective-c/sdwebimage/3.3/badge.svg?style=flat)](https://www.versioneye.com/objective-c/sdwebimage/3.3)
|
||||
[![Reference Status](https://www.versioneye.com/objective-c/sdwebimage/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/sdwebimage/references)
|
||||
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/rs/SDWebImage)
|
||||
[![codecov](https://codecov.io/gh/rs/SDWebImage/branch/testing/graph/badge.svg)](https://codecov.io/gh/rs/SDWebImage)
|
||||
|
||||
This library provides an async image downloader with cache support. For convenience, we added categories for some `UIControl` elements like `UIImageView`.
|
||||
|
||||
|
|
|
@ -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, ); }; };
|
||||
|
@ -435,6 +447,18 @@
|
|||
43A62A641D0E0A8F0089D7DD /* vp8li.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577D681998E6B2007367ED /* vp8li.h */; };
|
||||
43A62A651D0E0A8F0089D7DD /* webp.c in Sources */ = {isa = PBXBuildFile; fileRef = DA577D691998E6B2007367ED /* webp.c */; };
|
||||
43A62A661D0E0A8F0089D7DD /* webpi.h in Headers */ = {isa = PBXBuildFile; fileRef = DA577D6A1998E6B2007367ED /* webpi.h */; };
|
||||
43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 43A918621D8308FE00B3925F /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A918631D8308FE00B3925F /* SDImageCacheConfig.m */; };
|
||||
43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -879,9 +903,13 @@
|
|||
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; path = "NSImage+WebCache.h"; sourceTree = "<group>"; };
|
||||
4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage+WebCache.m"; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
43A918621D8308FE00B3925F /* SDImageCacheConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDImageCacheConfig.h; sourceTree = "<group>"; };
|
||||
43A918631D8308FE00B3925F /* SDImageCacheConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDImageCacheConfig.m; sourceTree = "<group>"; };
|
||||
43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImage.h; sourceTree = "<group>"; };
|
||||
43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImage.m; sourceTree = "<group>"; };
|
||||
43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImageView.h; sourceTree = "<group>"; };
|
||||
|
@ -985,8 +1013,8 @@
|
|||
A18A6CC6172DC28500419892 /* UIImage+GIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+GIF.m"; sourceTree = "<group>"; };
|
||||
AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+WebCacheOperation.h"; sourceTree = "<group>"; };
|
||||
AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+WebCacheOperation.m"; sourceTree = "<group>"; };
|
||||
ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+HighlightedWebCache.h"; sourceTree = "<group>"; };
|
||||
ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+HighlightedWebCache.m"; sourceTree = "<group>"; };
|
||||
ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = "<group>"; };
|
||||
ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = "<group>"; };
|
||||
DA577CA81998E60B007367ED /* bit_reader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bit_reader.c; sourceTree = "<group>"; };
|
||||
DA577CA91998E60B007367ED /* bit_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_reader.h; sourceTree = "<group>"; };
|
||||
DA577CAA1998E60B007367ED /* bit_reader_inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_reader_inl.h; sourceTree = "<group>"; };
|
||||
|
@ -1089,6 +1117,26 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
4369C2851D9811BB007E863A /* WebCache Categories */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */,
|
||||
4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */,
|
||||
535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */,
|
||||
535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */,
|
||||
53922D93148C56230056699D /* UIButton+WebCache.h */,
|
||||
53922D94148C56230056699D /* UIButton+WebCache.m */,
|
||||
ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */,
|
||||
ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */,
|
||||
53922D95148C56230056699D /* UIImageView+WebCache.h */,
|
||||
53922D96148C56230056699D /* UIImageView+WebCache.m */,
|
||||
4369C2751D9807EC007E863A /* UIView+WebCache.h */,
|
||||
4369C2761D9807EC007E863A /* UIView+WebCache.m */,
|
||||
);
|
||||
name = "WebCache Categories";
|
||||
path = ..;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
43CE75451CFE9427006C64D0 /* FLAnimatedImage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1181,6 +1229,7 @@
|
|||
53922DAA148C56470056699D /* Cache */,
|
||||
53922DAC148C56DD0056699D /* Utils */,
|
||||
53922DA9148C562D0056699D /* Categories */,
|
||||
4369C2851D9811BB007E863A /* WebCache Categories */,
|
||||
43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */,
|
||||
);
|
||||
path = SDWebImage;
|
||||
|
@ -1189,26 +1238,16 @@
|
|||
53922DA9148C562D0056699D /* Categories */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */,
|
||||
535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */,
|
||||
5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */,
|
||||
5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */,
|
||||
53922D93148C56230056699D /* UIButton+WebCache.h */,
|
||||
53922D94148C56230056699D /* UIButton+WebCache.m */,
|
||||
A18A6CC5172DC28500419892 /* UIImage+GIF.h */,
|
||||
A18A6CC6172DC28500419892 /* UIImage+GIF.m */,
|
||||
53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */,
|
||||
53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */,
|
||||
53EDFB911762547C00698166 /* UIImage+WebP.h */,
|
||||
53EDFB921762547C00698166 /* UIImage+WebP.m */,
|
||||
ABBE71A518C43B4D00B75E91 /* UIImageView+HighlightedWebCache.h */,
|
||||
ABBE71A618C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m */,
|
||||
53922D95148C56230056699D /* UIImageView+WebCache.h */,
|
||||
53922D96148C56230056699D /* UIImageView+WebCache.m */,
|
||||
AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */,
|
||||
AB615302192DA24600A2D8E9 /* UIView+WebCacheOperation.m */,
|
||||
4397D2F41D0DE2DF00BB2784 /* NSImage+WebCache.h */,
|
||||
4397D2F51D0DE2DF00BB2784 /* NSImage+WebCache.m */,
|
||||
);
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1218,6 +1257,8 @@
|
|||
children = (
|
||||
53922D85148C56230056699D /* SDImageCache.h */,
|
||||
53922D86148C56230056699D /* SDImageCache.m */,
|
||||
43A918621D8308FE00B3925F /* SDImageCacheConfig.h */,
|
||||
43A918631D8308FE00B3925F /* SDImageCacheConfig.m */,
|
||||
);
|
||||
name = Cache;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1413,10 +1454,12 @@
|
|||
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 */,
|
||||
431738E11CDFC8A40008FEB9 /* webpi.h in Headers */,
|
||||
43A918671D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
431739571CDFC8B70008FEB9 /* encode.h in Headers */,
|
||||
431739351CDFC8B20008FEB9 /* bit_reader.h in Headers */,
|
||||
43DA7D5D1D1086600028BE58 /* mips_macro.h in Headers */,
|
||||
|
@ -1488,6 +1531,7 @@
|
|||
43DA7CFE1D10865E0028BE58 /* yuv.h in Headers */,
|
||||
4314D1711D0E0E3B004B36C9 /* huffman.h in Headers */,
|
||||
4314D1721D0E0E3B004B36C9 /* SDWebImageCompat.h in Headers */,
|
||||
43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
4314D1731D0E0E3B004B36C9 /* vp8li.h in Headers */,
|
||||
4314D1741D0E0E3B004B36C9 /* types.h in Headers */,
|
||||
4314D1761D0E0E3B004B36C9 /* decode.h in Headers */,
|
||||
|
@ -1497,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 */,
|
||||
|
@ -1558,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 */,
|
||||
|
@ -1575,6 +1621,7 @@
|
|||
431BB6F91D06D2C1006A3455 /* UIImage+GIF.h in Headers */,
|
||||
431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */,
|
||||
431BB6FC1D06D2C1006A3455 /* SDWebImageDecoder.h in Headers */,
|
||||
43A918681D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1593,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 */,
|
||||
|
@ -1606,6 +1654,7 @@
|
|||
4397D2D11D0DDD8C00BB2784 /* decode.h in Headers */,
|
||||
4397D2D21D0DDD8C00BB2784 /* webpi.h in Headers */,
|
||||
43DA7DCB1D1086610028BE58 /* mips_macro.h in Headers */,
|
||||
43A918691D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
4397D2D31D0DDD8C00BB2784 /* thread.h in Headers */,
|
||||
4397D2D41D0DDD8C00BB2784 /* quant_levels.h in Headers */,
|
||||
4397D2D51D0DDD8C00BB2784 /* bit_reader_inl.h in Headers */,
|
||||
|
@ -1646,10 +1695,12 @@
|
|||
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 */,
|
||||
431739231CDFC8B20008FEB9 /* filters.h in Headers */,
|
||||
43A918661D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
4A2CAE211AB4BB7000B6BC39 /* SDWebImageManager.h in Headers */,
|
||||
4A2CAE1F1AB4BB6C00B6BC39 /* SDImageCache.h in Headers */,
|
||||
43DA7D261D10865F0028BE58 /* mips_macro.h in Headers */,
|
||||
|
@ -1728,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 */,
|
||||
|
@ -1755,6 +1807,7 @@
|
|||
53EDFB8A17623F7C00698166 /* UIImage+MultiFormat.h in Headers */,
|
||||
4317387B1CDFC2580008FEB9 /* decode_vp8.h in Headers */,
|
||||
431738B61CDFC2630008FEB9 /* random.h in Headers */,
|
||||
43A918641D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2017,6 +2070,7 @@
|
|||
43DA7D361D1086600028BE58 /* alpha_processing_sse41.c in Sources */,
|
||||
43DA7D641D1086600028BE58 /* upsampling_mips_dsp_r2.c in Sources */,
|
||||
431739461CDFC8B20008FEB9 /* random.c in Sources */,
|
||||
43A9186E1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
43DA7D3D1D1086600028BE58 /* cost_sse2.c in Sources */,
|
||||
431738DB1CDFC8A40008FEB9 /* tree.c in Sources */,
|
||||
00733A581BC4880000A5A117 /* SDWebImageManager.m in Sources */,
|
||||
|
@ -2060,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 */,
|
||||
|
@ -2091,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 */,
|
||||
|
@ -2119,6 +2175,7 @@
|
|||
43DA7CFD1D10865E0028BE58 /* yuv.c in Sources */,
|
||||
4314D1401D0E0E3B004B36C9 /* UIImageView+WebCache.m in Sources */,
|
||||
43DA7CDC1D10865E0028BE58 /* enc_mips32.c in Sources */,
|
||||
43A9186C1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
4314D1411D0E0E3B004B36C9 /* SDWebImageDownloaderOperation.m in Sources */,
|
||||
43DA7CCE1D10865E0028BE58 /* cost_mips32.c in Sources */,
|
||||
4314D1421D0E0E3B004B36C9 /* webp.c in Sources */,
|
||||
|
@ -2187,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 */,
|
||||
|
@ -2215,6 +2273,7 @@
|
|||
43DA7DA21D1086600028BE58 /* yuv.c in Sources */,
|
||||
431BB6B91D06D2C1006A3455 /* UIButton+WebCache.m in Sources */,
|
||||
43DA7D811D1086600028BE58 /* enc_mips32.c in Sources */,
|
||||
43A9186F1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
43A62A5F1D0E0A8F0089D7DD /* quant.c in Sources */,
|
||||
43DA7D731D1086600028BE58 /* cost_mips32.c in Sources */,
|
||||
431BB6BD1D06D2C1006A3455 /* UIImage+GIF.m in Sources */,
|
||||
|
@ -2335,11 +2394,13 @@
|
|||
4397D2AA1D0DDD8C00BB2784 /* io.c in Sources */,
|
||||
43DA7DCF1D1086610028BE58 /* rescaler_neon.c in Sources */,
|
||||
43DA7DC31D1086610028BE58 /* lossless_enc_sse2.c in Sources */,
|
||||
43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */,
|
||||
43DA7DA91D1086610028BE58 /* cost_mips_dsp_r2.c in Sources */,
|
||||
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 */,
|
||||
|
@ -2407,6 +2468,7 @@
|
|||
43DA7CFF1D10865F0028BE58 /* alpha_processing_sse41.c in Sources */,
|
||||
43DA7D2D1D10865F0028BE58 /* upsampling_mips_dsp_r2.c in Sources */,
|
||||
4A2CAE261AB4BB7000B6BC39 /* SDWebImagePrefetcher.m in Sources */,
|
||||
43A9186D1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
43DA7D061D10865F0028BE58 /* cost_sse2.c in Sources */,
|
||||
4317391F1CDFC8B20008FEB9 /* color_cache.c in Sources */,
|
||||
4A2CAE301AB4BB7500B6BC39 /* UIImage+MultiFormat.m in Sources */,
|
||||
|
@ -2450,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 */,
|
||||
|
@ -2507,6 +2570,7 @@
|
|||
43DA7C911D1086570028BE58 /* alpha_processing_sse41.c in Sources */,
|
||||
43DA7CBF1D1086570028BE58 /* upsampling_mips_dsp_r2.c in Sources */,
|
||||
5376130D155AD0D5005750A4 /* SDWebImagePrefetcher.m in Sources */,
|
||||
43A9186B1D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
|
||||
43DA7C981D1086570028BE58 /* cost_sse2.c in Sources */,
|
||||
431738A81CDFC2630008FEB9 /* color_cache.c in Sources */,
|
||||
5376130E155AD0D5005750A4 /* UIButton+WebCache.m in Sources */,
|
||||
|
@ -2550,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 */,
|
||||
|
@ -2847,7 +2912,6 @@
|
|||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"SD_WEBP=1",
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
|
@ -2901,10 +2965,7 @@
|
|||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"SD_WEBP=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
NSString *imageContentType = [NSData sd_contentTypeForImageData:data];
|
||||
if ([imageContentType isEqualToString:@"image/gif"]) {
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,15 +9,24 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, SDImageFormat) {
|
||||
SDImageFormatUndefined = -1,
|
||||
SDImageFormatJPEG = 0,
|
||||
SDImageFormatPNG,
|
||||
SDImageFormatGIF,
|
||||
SDImageFormatTIFF,
|
||||
SDImageFormatWebP
|
||||
};
|
||||
|
||||
@interface NSData (ImageContentType)
|
||||
|
||||
/**
|
||||
* Compute the content type for an image data
|
||||
* Return image format
|
||||
*
|
||||
* @param data the input data
|
||||
* @param data the input image data
|
||||
*
|
||||
* @return the content type as string (i.e. image/jpeg, image/gif)
|
||||
* @return the image format as `SDImageFormat` (enum)
|
||||
*/
|
||||
+ (nullable NSString *)sd_contentTypeForImageData:(nullable NSData *)data;
|
||||
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;
|
||||
|
||||
@end
|
||||
|
|
|
@ -12,37 +12,35 @@
|
|||
|
||||
@implementation NSData (ImageContentType)
|
||||
|
||||
+ (nullable NSString *)sd_contentTypeForImageData:(nullable NSData *)data {
|
||||
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
|
||||
if (!data) {
|
||||
return nil;
|
||||
return SDImageFormatUndefined;
|
||||
}
|
||||
|
||||
|
||||
uint8_t c;
|
||||
[data getBytes:&c length:1];
|
||||
switch (c) {
|
||||
case 0xFF:
|
||||
return @"image/jpeg";
|
||||
return SDImageFormatJPEG;
|
||||
case 0x89:
|
||||
return @"image/png";
|
||||
return SDImageFormatPNG;
|
||||
case 0x47:
|
||||
return @"image/gif";
|
||||
return SDImageFormatGIF;
|
||||
case 0x49:
|
||||
case 0x4D:
|
||||
return @"image/tiff";
|
||||
return SDImageFormatTIFF;
|
||||
case 0x52:
|
||||
// R as RIFF for WEBP
|
||||
if (data.length < 12) {
|
||||
return nil;
|
||||
return SDImageFormatUndefined;
|
||||
}
|
||||
|
||||
|
||||
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
|
||||
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
|
||||
return @"image/webp";
|
||||
return SDImageFormatWebP;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
return nil;
|
||||
return SDImageFormatUndefined;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "SDWebImageCompat.h"
|
||||
|
||||
@class SDImageCacheConfig;
|
||||
|
||||
typedef NS_ENUM(NSInteger, SDImageCacheType) {
|
||||
/**
|
||||
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
|
||||
|
@ -30,27 +32,19 @@ typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache);
|
|||
|
||||
typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize);
|
||||
|
||||
|
||||
/**
|
||||
* SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed
|
||||
* asynchronous so it doesn’t add unnecessary latency to the UI.
|
||||
*/
|
||||
@interface SDImageCache : NSObject
|
||||
|
||||
/**
|
||||
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
|
||||
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldDecompressImages;
|
||||
#pragma mark - Properties
|
||||
|
||||
/**
|
||||
* disable iCloud backup [defaults to YES]
|
||||
* Cache Config object - storing all kind of settings
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldDisableiCloud;
|
||||
|
||||
/**
|
||||
* use memory cache [defaults to YES]
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
|
||||
@property (nonatomic, nonnull, readonly) SDImageCacheConfig *config;
|
||||
|
||||
/**
|
||||
* The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory.
|
||||
|
@ -62,15 +56,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
|
|||
*/
|
||||
@property (assign, nonatomic) NSUInteger maxMemoryCountLimit;
|
||||
|
||||
/**
|
||||
* The maximum length of time to keep an image in the cache, in seconds
|
||||
*/
|
||||
@property (assign, nonatomic) NSInteger maxCacheAge;
|
||||
|
||||
/**
|
||||
* The maximum size of the cache, in bytes.
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger maxCacheSize;
|
||||
#pragma mark - Singleton and initialization
|
||||
|
||||
/**
|
||||
* Returns global shared cache instance
|
||||
|
@ -95,6 +81,8 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
|
|||
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns
|
||||
diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
#pragma mark - Cache paths
|
||||
|
||||
- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace;
|
||||
|
||||
/**
|
||||
|
@ -105,126 +93,140 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
|
|||
*/
|
||||
- (void)addReadOnlyCachePath:(nonnull NSString *)path;
|
||||
|
||||
/**
|
||||
* Store an image into memory and disk cache at the given key.
|
||||
*
|
||||
* @param image The image to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
*/
|
||||
- (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key;
|
||||
#pragma mark - Store Ops
|
||||
|
||||
/**
|
||||
* Store an image into memory and optionally disk cache at the given key.
|
||||
* Asynchronously store an image into memory and disk cache at the given key.
|
||||
*
|
||||
* @param image The image to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param toDisk Store the image to disk cache if YES
|
||||
* @param image The image to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param completion A block executed after the operation is finished
|
||||
*/
|
||||
- (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk;
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
forKey:(nullable NSString *)key
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Store an image into memory and optionally disk cache at the given key.
|
||||
* Asynchronously store an image into memory and disk cache at the given key.
|
||||
*
|
||||
* @param image The image to store
|
||||
* @param recalculate BOOL indicates if imageData can be used or a new data should be constructed from the UIImage
|
||||
* @param imageData The image data as returned by the server, this representation will be used for disk storage
|
||||
* instead of converting the given image object into a storable/compressed image format in order
|
||||
* to save quality and CPU
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param toDisk Store the image to disk cache if YES
|
||||
* @param image The image to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param toDisk Store the image to disk cache if YES
|
||||
* @param completion A block executed after the operation is finished
|
||||
*/
|
||||
- (void)storeImage:(nullable UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk;
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
forKey:(nullable NSString *)key
|
||||
toDisk:(BOOL)toDisk
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Store image NSData into disk cache at the given key.
|
||||
* Asynchronously store an image into memory and disk cache at the given key.
|
||||
*
|
||||
* @param imageData The image data to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param image The image to store
|
||||
* @param imageData The image data as returned by the server, this representation will be used for disk storage
|
||||
* instead of converting the given image object into a storable/compressed image format in order
|
||||
* to save quality and CPU
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
* @param toDisk Store the image to disk cache if YES
|
||||
* @param completion A block executed after the operation is finished
|
||||
*/
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
imageData:(nullable NSData *)imageData
|
||||
forKey:(nullable NSString *)key
|
||||
toDisk:(BOOL)toDisk
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Synchronously store image NSData into disk cache at the given key.
|
||||
*
|
||||
* @warning This method is synchronous, make sure to call it from the ioQueue
|
||||
*
|
||||
* @param imageData The image data to store
|
||||
* @param key The unique image cache key, usually it's image absolute URL
|
||||
*/
|
||||
- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key;
|
||||
|
||||
#pragma mark - Query and Retrieve Ops
|
||||
|
||||
/**
|
||||
* Query the disk cache asynchronously.
|
||||
* Async check if image exists in disk cache already (does not load the image)
|
||||
*
|
||||
* @param key The unique key used to store the wanted image
|
||||
* @param key the key describing the url
|
||||
* @param completionBlock the block to be executed when the check is done.
|
||||
* @note the completion block will be always executed on the main queue
|
||||
*/
|
||||
- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock;
|
||||
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Operation that queries the cache asynchronously and call the completion when done.
|
||||
*
|
||||
* @param key The unique key used to store the wanted image
|
||||
* @param doneBlock The completion block. Will not get called if the operation is cancelled
|
||||
*
|
||||
* @return a NSOperation instance containing the cache op
|
||||
*/
|
||||
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock;
|
||||
|
||||
/**
|
||||
* Query the memory cache synchronously.
|
||||
*
|
||||
* @param key The unique key used to store the wanted image
|
||||
* @param key The unique key used to store the image
|
||||
*/
|
||||
- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key;
|
||||
|
||||
/**
|
||||
* Query the disk cache synchronously after checking the memory cache.
|
||||
* Query the disk cache synchronously.
|
||||
*
|
||||
* @param key The unique key used to store the wanted image
|
||||
* @param key The unique key used to store the image
|
||||
*/
|
||||
- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key;
|
||||
|
||||
/**
|
||||
* Remove the image from memory and disk cache asynchronously
|
||||
* Query the cache (memory and or disk) synchronously after checking the memory cache.
|
||||
*
|
||||
* @param key The unique image cache key
|
||||
* @param key The unique key used to store the image
|
||||
*/
|
||||
- (void)removeImageForKey:(nullable NSString *)key;
|
||||
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key;
|
||||
|
||||
#pragma mark - Remove Ops
|
||||
|
||||
/**
|
||||
* Remove the image from memory and disk cache asynchronously
|
||||
*
|
||||
* @param key The unique image cache key
|
||||
* @param completion An block that should be executed after the image has been removed (optional)
|
||||
* @param completion A block that should be executed after the image has been removed (optional)
|
||||
*/
|
||||
- (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion;
|
||||
|
||||
/**
|
||||
* Remove the image from memory and optionally disk cache asynchronously
|
||||
*
|
||||
* @param key The unique image cache key
|
||||
* @param fromDisk Also remove cache entry from disk if YES
|
||||
*/
|
||||
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk;
|
||||
|
||||
/**
|
||||
* Remove the image from memory and optionally disk cache asynchronously
|
||||
*
|
||||
* @param key The unique image cache key
|
||||
* @param fromDisk Also remove cache entry from disk if YES
|
||||
* @param completion An block that should be executed after the image has been removed (optional)
|
||||
* @param completion A block that should be executed after the image has been removed (optional)
|
||||
*/
|
||||
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion;
|
||||
|
||||
#pragma mark - Cache clean Ops
|
||||
|
||||
/**
|
||||
* Clear all memory cached images
|
||||
*/
|
||||
- (void)clearMemory;
|
||||
|
||||
/**
|
||||
* Clear all disk cached images. Non-blocking method - returns immediately.
|
||||
* @param completion An block that should be executed after cache expiration completes (optional)
|
||||
* Async clear all disk cached images. Non-blocking method - returns immediately.
|
||||
* @param completion A block that should be executed after cache expiration completes (optional)
|
||||
*/
|
||||
- (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion;
|
||||
|
||||
/**
|
||||
* Clear all disk cached images
|
||||
* @see clearDiskOnCompletion:
|
||||
* Async remove all expired cached image from disk. Non-blocking method - returns immediately.
|
||||
* @param completionBlock A block that should be executed after cache expiration completes (optional)
|
||||
*/
|
||||
- (void)clearDisk;
|
||||
- (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Remove all expired cached image from disk. Non-blocking method - returns immediately.
|
||||
* @param completionBlock An block that should be executed after cache expiration completes (optional)
|
||||
*/
|
||||
- (void)cleanDiskWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Remove all expired cached image from disk
|
||||
* @see cleanDiskWithCompletionBlock:
|
||||
*/
|
||||
- (void)cleanDisk;
|
||||
#pragma mark - Cache Info
|
||||
|
||||
/**
|
||||
* Get the size used by the disk cache
|
||||
|
@ -241,23 +243,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
|
|||
*/
|
||||
- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Async check if image exists in disk cache already (does not load the image)
|
||||
*
|
||||
* @param key the key describing the url
|
||||
* @param completionBlock the block to be executed when the check is done.
|
||||
* @note the completion block will be always executed on the main queue
|
||||
*/
|
||||
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* Check if image exists in disk cache already (does not load the image)
|
||||
*
|
||||
* @param key the key describing the url
|
||||
*
|
||||
* @return YES if an image exists for the given key
|
||||
*/
|
||||
- (BOOL)diskImageExistsWithKey:(nullable NSString *)key;
|
||||
#pragma mark - Cache Paths
|
||||
|
||||
/**
|
||||
* Get the cache path for a certain key (needs the cache path root folder)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#import "UIImage+GIF.h"
|
||||
#import "NSData+ImageContentType.h"
|
||||
#import "NSImage+WebCache.h"
|
||||
#import "SDImageCacheConfig.h"
|
||||
|
||||
// See https://github.com/rs/SDWebImage/pull/1141 for discussion
|
||||
@interface AutoPurgeCache : NSCache
|
||||
|
@ -38,23 +39,6 @@
|
|||
|
||||
@end
|
||||
|
||||
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
||||
// PNG signature bytes and data (below)
|
||||
static unsigned char kPNGSignatureBytes[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
static NSData *kPNGSignatureData = nil;
|
||||
|
||||
BOOL ImageDataHasPNGPreffix(NSData *data);
|
||||
|
||||
BOOL ImageDataHasPNGPreffix(NSData *data) {
|
||||
NSUInteger pngSignatureLength = kPNGSignatureData.length;
|
||||
if (data.length >= pngSignatureLength) {
|
||||
if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
||||
#if SD_MAC
|
||||
|
@ -66,6 +50,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
|
||||
@interface SDImageCache ()
|
||||
|
||||
#pragma mark - Properties
|
||||
@property (strong, nonatomic, nonnull) NSCache *memCache;
|
||||
@property (strong, nonatomic, nonnull) NSString *diskCachePath;
|
||||
@property (strong, nonatomic, nullable) NSMutableArray<NSString *> *customPaths;
|
||||
|
@ -78,6 +63,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
NSFileManager *_fileManager;
|
||||
}
|
||||
|
||||
#pragma mark - Singleton, init, dealloc
|
||||
|
||||
+ (nonnull SDImageCache *)sharedImageCache {
|
||||
static dispatch_once_t once;
|
||||
static id instance;
|
||||
|
@ -100,16 +87,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
diskCacheDirectory:(nonnull NSString *)directory {
|
||||
if ((self = [super init])) {
|
||||
NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];
|
||||
|
||||
// initialise PNG signature data
|
||||
kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8];
|
||||
|
||||
|
||||
// Create IO serial queue
|
||||
_ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
// Init default values
|
||||
_maxCacheAge = kDefaultCacheMaxCacheAge;
|
||||
|
||||
|
||||
_config = [[SDImageCacheConfig alloc] init];
|
||||
|
||||
// Init the memory cache
|
||||
_memCache = [[AutoPurgeCache alloc] init];
|
||||
_memCache.name = fullNamespace;
|
||||
|
@ -122,15 +105,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
_diskCachePath = path;
|
||||
}
|
||||
|
||||
// Set decompression to YES
|
||||
_shouldDecompressImages = YES;
|
||||
|
||||
// memory cache enabled
|
||||
_shouldCacheImagesInMemory = YES;
|
||||
|
||||
// Disable iCloud
|
||||
_shouldDisableiCloud = YES;
|
||||
|
||||
dispatch_sync(_ioQueue, ^{
|
||||
_fileManager = [NSFileManager new];
|
||||
});
|
||||
|
@ -143,12 +117,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(cleanDisk)
|
||||
selector:@selector(deleteOldFiles)
|
||||
name:UIApplicationWillTerminateNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(backgroundCleanDisk)
|
||||
selector:@selector(backgroundDeleteOldFiles)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
#endif
|
||||
|
@ -162,6 +136,16 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
SDDispatchQueueRelease(_ioQueue);
|
||||
}
|
||||
|
||||
- (void)checkIfQueueIsIOQueue {
|
||||
const char *currentQueueLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
|
||||
const char *ioQueueLabel = dispatch_queue_get_label(self.ioQueue);
|
||||
if (strcmp(currentQueueLabel, ioQueueLabel) != 0) {
|
||||
NSLog(@"This method should be called from the ioQueue");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Cache paths
|
||||
|
||||
- (void)addReadOnlyCachePath:(nonnull NSString *)path {
|
||||
if (!self.customPaths) {
|
||||
self.customPaths = [NSMutableArray new];
|
||||
|
@ -181,8 +165,6 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
return [self cachePathForKey:key inPath:self.diskCachePath];
|
||||
}
|
||||
|
||||
#pragma mark SDImageCache (private)
|
||||
|
||||
- (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key {
|
||||
const char *str = key.UTF8String;
|
||||
if (str == NULL) {
|
||||
|
@ -197,88 +179,73 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
return filename;
|
||||
}
|
||||
|
||||
#pragma mark ImageCache
|
||||
|
||||
// Init the disk cache
|
||||
- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace {
|
||||
NSArray<NSString *> *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
return [paths[0] stringByAppendingPathComponent:fullNamespace];
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk {
|
||||
#pragma mark - Store Ops
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
forKey:(nullable NSString *)key
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
|
||||
[self storeImage:image imageData:nil forKey:key toDisk:YES completion:completionBlock];
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
forKey:(nullable NSString *)key
|
||||
toDisk:(BOOL)toDisk
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
|
||||
[self storeImage:image imageData:nil forKey:key toDisk:toDisk completion:completionBlock];
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image
|
||||
imageData:(nullable NSData *)imageData
|
||||
forKey:(nullable NSString *)key
|
||||
toDisk:(BOOL)toDisk
|
||||
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
|
||||
if (!image || !key) {
|
||||
if (completionBlock) {
|
||||
completionBlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// if memory cache is enabled
|
||||
if (self.shouldCacheImagesInMemory) {
|
||||
if (self.config.shouldCacheImagesInMemory) {
|
||||
NSUInteger cost = SDCacheCostForImage(image);
|
||||
[self.memCache setObject:image forKey:key cost:cost];
|
||||
}
|
||||
|
||||
|
||||
if (toDisk) {
|
||||
dispatch_async(self.ioQueue, ^{
|
||||
NSData *data = imageData;
|
||||
|
||||
if (image && (recalculate || !data)) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
// We need to determine if the image is a PNG or a JPEG
|
||||
// PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)
|
||||
// The first eight bytes of a PNG file always contain the following (decimal) values:
|
||||
// 137 80 78 71 13 10 26 10
|
||||
|
||||
// If the imageData is nil (i.e. if trying to save a UIImage directly or the image was transformed on download)
|
||||
// and the image has an alpha channel, we will consider it PNG to avoid losing the transparency
|
||||
int alphaInfo = CGImageGetAlphaInfo(image.CGImage);
|
||||
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
|
||||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
|
||||
alphaInfo == kCGImageAlphaNoneSkipLast);
|
||||
BOOL imageIsPng = hasAlpha;
|
||||
|
||||
// But if we have an image data, we will look at the preffix
|
||||
if (imageData.length >= kPNGSignatureData.length) {
|
||||
imageIsPng = ImageDataHasPNGPreffix(imageData);
|
||||
}
|
||||
|
||||
if (imageIsPng) {
|
||||
data = UIImagePNGRepresentation(image);
|
||||
}
|
||||
else {
|
||||
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
|
||||
}
|
||||
#else
|
||||
NSString *contentType = [NSData sd_contentTypeForImageData:data];
|
||||
NSBitmapImageFileType imageFileType = NSJPEGFileType;
|
||||
if ([contentType isEqualToString:@"image/gif"]) {
|
||||
imageFileType = NSGIFFileType;
|
||||
} else if ([contentType isEqualToString:@"image/png"]) {
|
||||
imageFileType = NSPNGFileType;
|
||||
}
|
||||
|
||||
data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations
|
||||
usingType:imageFileType
|
||||
properties:@{}];
|
||||
#endif
|
||||
|
||||
if (!data && image) {
|
||||
SDImageFormat imageFormatFromData = [NSData sd_imageFormatForImageData:data];
|
||||
data = [image sd_imageDataAsFormat:imageFormatFromData];
|
||||
}
|
||||
|
||||
|
||||
[self storeImageDataToDisk:data forKey:key];
|
||||
if (completionBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (completionBlock) {
|
||||
completionBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key {
|
||||
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:YES];
|
||||
}
|
||||
|
||||
- (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk {
|
||||
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:toDisk];
|
||||
}
|
||||
|
||||
- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key {
|
||||
|
||||
if (!imageData) {
|
||||
if (!imageData || !key) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self checkIfQueueIsIOQueue];
|
||||
|
||||
if (![_fileManager fileExistsAtPath:_diskCachePath]) {
|
||||
[_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
}
|
||||
|
@ -291,26 +258,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
[_fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil];
|
||||
|
||||
// disable iCloud backup
|
||||
if (self.shouldDisableiCloud) {
|
||||
if (self.config.shouldDisableiCloud) {
|
||||
[fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)diskImageExistsWithKey:(nullable NSString *)key {
|
||||
BOOL exists = NO;
|
||||
|
||||
// this is an exception to access the filemanager on another queue than ioQueue, but we are using the shared instance
|
||||
// from apple docs on NSFileManager: The methods of the shared NSFileManager object can be called from multiple threads safely.
|
||||
exists = [[NSFileManager defaultManager] fileExistsAtPath:[self defaultCachePathForKey:key]];
|
||||
|
||||
// fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name
|
||||
// checking the key with and without the extension
|
||||
if (!exists) {
|
||||
exists = [[NSFileManager defaultManager] fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension];
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
#pragma mark - Query and Retrieve Ops
|
||||
|
||||
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
|
||||
dispatch_async(_ioQueue, ^{
|
||||
|
@ -335,16 +288,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
}
|
||||
|
||||
- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key {
|
||||
|
||||
// First check the in-memory cache...
|
||||
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
||||
if (image) {
|
||||
return image;
|
||||
}
|
||||
|
||||
// Second check the disk cache...
|
||||
UIImage *diskImage = [self diskImageForKey:key];
|
||||
if (diskImage && self.shouldCacheImagesInMemory) {
|
||||
if (diskImage && self.config.shouldCacheImagesInMemory) {
|
||||
NSUInteger cost = SDCacheCostForImage(diskImage);
|
||||
[self.memCache setObject:diskImage forKey:key cost:cost];
|
||||
}
|
||||
|
@ -352,6 +297,18 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
return diskImage;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key {
|
||||
// First check the in-memory cache...
|
||||
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
||||
if (image) {
|
||||
return image;
|
||||
}
|
||||
|
||||
// Second check the disk cache...
|
||||
image = [self imageFromDiskCacheForKey:key];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key {
|
||||
NSString *defaultPath = [self defaultCachePathForKey:key];
|
||||
NSData *data = [NSData dataWithContentsOfFile:defaultPath];
|
||||
|
@ -390,7 +347,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
if (data) {
|
||||
UIImage *image = [UIImage sd_imageWithData:data];
|
||||
image = [self scaledImageForKey:key image:image];
|
||||
if (self.shouldDecompressImages) {
|
||||
if (self.config.shouldDecompressImages) {
|
||||
image = [UIImage decodedImageWithImage:image];
|
||||
}
|
||||
return image;
|
||||
|
@ -404,13 +361,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
return SDScaledImageForKey(key, image);
|
||||
}
|
||||
|
||||
- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {
|
||||
if (!doneBlock) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock {
|
||||
if (!key) {
|
||||
doneBlock(nil, nil, SDImageCacheTypeNone);
|
||||
if (doneBlock) {
|
||||
doneBlock(nil, nil, SDImageCacheTypeNone);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -421,52 +376,50 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
if ([image isGIF]) {
|
||||
diskData = [self diskImageDataBySearchingAllPathsForKey:key];
|
||||
}
|
||||
doneBlock(image, diskData, SDImageCacheTypeMemory);
|
||||
if (doneBlock) {
|
||||
doneBlock(image, diskData, SDImageCacheTypeMemory);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSOperation *operation = [NSOperation new];
|
||||
dispatch_async(self.ioQueue, ^{
|
||||
if (operation.isCancelled) {
|
||||
// do not call the completion if cancelled
|
||||
return;
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
|
||||
UIImage *diskImage = [self diskImageForKey:key];
|
||||
if (diskImage && self.shouldCacheImagesInMemory) {
|
||||
if (diskImage && self.config.shouldCacheImagesInMemory) {
|
||||
NSUInteger cost = SDCacheCostForImage(diskImage);
|
||||
[self.memCache setObject:diskImage forKey:key cost:cost];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
|
||||
});
|
||||
if (doneBlock) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
doneBlock(diskImage, diskData, SDImageCacheTypeDisk);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
- (void)removeImageForKey:(nullable NSString *)key {
|
||||
[self removeImageForKey:key withCompletion:nil];
|
||||
}
|
||||
#pragma mark - Remove Ops
|
||||
|
||||
- (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion {
|
||||
[self removeImageForKey:key fromDisk:YES withCompletion:completion];
|
||||
}
|
||||
|
||||
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk {
|
||||
[self removeImageForKey:key fromDisk:fromDisk withCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion {
|
||||
|
||||
if (key == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.shouldCacheImagesInMemory) {
|
||||
if (self.config.shouldCacheImagesInMemory) {
|
||||
[self.memCache removeObjectForKey:key];
|
||||
}
|
||||
|
||||
|
@ -486,6 +439,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
|
||||
}
|
||||
|
||||
# pragma mark - Mem Cache settings
|
||||
|
||||
- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost {
|
||||
self.memCache.totalCostLimit = maxMemoryCost;
|
||||
}
|
||||
|
@ -502,14 +457,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
self.memCache.countLimit = maxCountLimit;
|
||||
}
|
||||
|
||||
#pragma mark - Cache clean Ops
|
||||
|
||||
- (void)clearMemory {
|
||||
[self.memCache removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)clearDisk {
|
||||
[self clearDiskOnCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion {
|
||||
dispatch_async(self.ioQueue, ^{
|
||||
[_fileManager removeItemAtPath:self.diskCachePath error:nil];
|
||||
|
@ -526,11 +479,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
});
|
||||
}
|
||||
|
||||
- (void)cleanDisk {
|
||||
[self cleanDiskWithCompletionBlock:nil];
|
||||
- (void)deleteOldFiles {
|
||||
[self deleteOldFilesWithCompletionBlock:nil];
|
||||
}
|
||||
|
||||
- (void)cleanDiskWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock {
|
||||
- (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock {
|
||||
dispatch_async(self.ioQueue, ^{
|
||||
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
|
||||
NSArray<NSString *> *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
|
||||
|
@ -541,7 +494,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
options:NSDirectoryEnumerationSkipsHiddenFiles
|
||||
errorHandler:NULL];
|
||||
|
||||
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
|
||||
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge];
|
||||
NSMutableDictionary<NSURL *, NSDictionary<NSString *, id> *> *cacheFiles = [NSMutableDictionary dictionary];
|
||||
NSUInteger currentCacheSize = 0;
|
||||
|
||||
|
@ -577,9 +530,9 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
|
||||
// If our remaining disk cache exceeds a configured maximum size, perform a second
|
||||
// size-based cleanup pass. We delete the oldest files first.
|
||||
if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize) {
|
||||
if (self.config.maxCacheSize > 0 && currentCacheSize > self.config.maxCacheSize) {
|
||||
// Target half of our maximum cache size for this cleanup pass.
|
||||
const NSUInteger desiredCacheSize = self.maxCacheSize / 2;
|
||||
const NSUInteger desiredCacheSize = self.config.maxCacheSize / 2;
|
||||
|
||||
// Sort the remaining cache files by their last modification time (oldest first).
|
||||
NSArray<NSURL *> *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
|
||||
|
@ -609,7 +562,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
}
|
||||
|
||||
#if SD_UIKIT
|
||||
- (void)backgroundCleanDisk {
|
||||
- (void)backgroundDeleteOldFiles {
|
||||
Class UIApplicationClass = NSClassFromString(@"UIApplication");
|
||||
if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) {
|
||||
return;
|
||||
|
@ -623,13 +576,15 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
}];
|
||||
|
||||
// Start the long-running task and return immediately.
|
||||
[self cleanDiskWithCompletionBlock:^{
|
||||
[self deleteOldFilesWithCompletionBlock:^{
|
||||
[application endBackgroundTask:bgTask];
|
||||
bgTask = UIBackgroundTaskInvalid;
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - Cache Info
|
||||
|
||||
- (NSUInteger)getSize {
|
||||
__block NSUInteger size = 0;
|
||||
dispatch_sync(self.ioQueue, ^{
|
||||
|
@ -680,3 +635,4 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// SDImageCacheConfig.h
|
||||
// SDWebImage
|
||||
//
|
||||
// Created by Bogdan on 09/09/16.
|
||||
// Copyright © 2016 Dailymotion. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SDImageCacheConfig : NSObject
|
||||
|
||||
/**
|
||||
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
|
||||
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldDecompressImages;
|
||||
|
||||
/**
|
||||
* disable iCloud backup [defaults to YES]
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldDisableiCloud;
|
||||
|
||||
/**
|
||||
* use memory cache [defaults to YES]
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
|
||||
|
||||
/**
|
||||
* The maximum length of time to keep an image in the cache, in seconds
|
||||
*/
|
||||
@property (assign, nonatomic) NSInteger maxCacheAge;
|
||||
|
||||
/**
|
||||
* The maximum size of the cache, in bytes.
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger maxCacheSize;
|
||||
|
||||
@end
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// SDImageCacheConfig.m
|
||||
// SDWebImage
|
||||
//
|
||||
// Created by Bogdan on 09/09/16.
|
||||
// Copyright © 2016 Dailymotion. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SDImageCacheConfig.h"
|
||||
|
||||
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
||||
|
||||
@implementation SDImageCacheConfig
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_shouldDecompressImages = YES;
|
||||
_shouldDisableiCloud = YES;
|
||||
_shouldCacheImagesInMemory = YES;
|
||||
_maxCacheAge = kDefaultCacheMaxCacheAge;
|
||||
_maxCacheSize = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
|
@ -112,3 +112,5 @@ extern NSString *const SDWebImageErrorDomain;
|
|||
} else {\
|
||||
dispatch_async(dispatch_get_main_queue(), block);\
|
||||
}
|
||||
|
||||
static int64_t kAsyncTestTimeout = 5;
|
||||
|
|
|
@ -97,6 +97,9 @@ typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterB
|
|||
*/
|
||||
@property (assign, nonatomic) BOOL shouldDecompressImages;
|
||||
|
||||
/**
|
||||
* The maximum number of concurrent downloads
|
||||
*/
|
||||
@property (assign, nonatomic) NSInteger maxConcurrentDownloads;
|
||||
|
||||
/**
|
||||
|
|
|
@ -129,7 +129,11 @@
|
|||
}
|
||||
|
||||
- (void)setOperationClass:(nullable Class)operationClass {
|
||||
_operationClass = operationClass ?: [SDWebImageDownloaderOperation class];
|
||||
if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) {
|
||||
_operationClass = operationClass;
|
||||
} else {
|
||||
_operationClass = [SDWebImageDownloaderOperation class];
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
|
||||
|
|
|
@ -15,7 +15,30 @@ extern NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification;
|
|||
extern NSString * _Nonnull const SDWebImageDownloadStopNotification;
|
||||
extern NSString * _Nonnull const SDWebImageDownloadFinishNotification;
|
||||
|
||||
@interface SDWebImageDownloaderOperation : NSOperation <SDWebImageOperation, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
|
||||
|
||||
|
||||
/**
|
||||
Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol
|
||||
*/
|
||||
@protocol SDWebImageDownloaderOperationInterface<NSObject>
|
||||
|
||||
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
|
||||
inSession:(nullable NSURLSession *)session
|
||||
options:(SDWebImageDownloaderOptions)options;
|
||||
|
||||
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
|
||||
|
||||
- (BOOL)shouldDecompressImages;
|
||||
- (void)setShouldDecompressImages:(BOOL)value;
|
||||
|
||||
- (nullable NSURLCredential *)credential;
|
||||
- (void)setCredential:(nullable NSURLCredential *)value;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface SDWebImageDownloaderOperation : NSOperation <SDWebImageDownloaderOperationInterface, SDWebImageOperation, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
|
||||
|
||||
/**
|
||||
* The request used by the operation's task.
|
||||
|
|
|
@ -39,7 +39,6 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
|
||||
@property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask;
|
||||
|
||||
@property (strong, atomic, nullable) NSThread *thread;
|
||||
@property (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t barrierQueue;
|
||||
|
||||
#if SD_UIKIT
|
||||
|
@ -164,7 +163,6 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
|
||||
self.dataTask = [session dataTaskWithRequest:self.request];
|
||||
self.executing = YES;
|
||||
self.thread = [NSThread currentThread];
|
||||
}
|
||||
|
||||
[self.dataTask resume];
|
||||
|
@ -197,20 +195,10 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
|
||||
- (void)cancel {
|
||||
@synchronized (self) {
|
||||
if (self.thread) {
|
||||
[self performSelector:@selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO];
|
||||
}
|
||||
else {
|
||||
[self cancelInternal];
|
||||
}
|
||||
[self cancelInternal];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelInternalAndStop {
|
||||
if (self.isFinished) return;
|
||||
[self cancelInternal];
|
||||
}
|
||||
|
||||
- (void)cancelInternal {
|
||||
if (self.isFinished) return;
|
||||
[super cancel];
|
||||
|
@ -242,7 +230,6 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
|
|||
});
|
||||
self.dataTask = nil;
|
||||
self.imageData = nil;
|
||||
self.thread = nil;
|
||||
if (self.ownedSession) {
|
||||
[self.ownedSession invalidateAndCancel];
|
||||
self.ownedSession = nil;
|
||||
|
@ -423,7 +410,6 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
||||
NSArray<id> *completionBlocks = [[self callbacksForKey:kCompletedCallbackKey] copy];
|
||||
@synchronized(self) {
|
||||
self.thread = nil;
|
||||
self.dataTask = nil;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
|
||||
|
|
|
@ -236,24 +236,6 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
|
|||
*/
|
||||
- (BOOL)isRunning;
|
||||
|
||||
/**
|
||||
* Check if image has already been cached
|
||||
*
|
||||
* @param url image url
|
||||
*
|
||||
* @return if the image was already cached
|
||||
*/
|
||||
- (BOOL)cachedImageExistsForURL:(nullable NSURL *)url;
|
||||
|
||||
/**
|
||||
* Check if image has already been cached on disk only
|
||||
*
|
||||
* @param url image url
|
||||
*
|
||||
* @return if the image was already cached (disk only)
|
||||
*/
|
||||
- (BOOL)diskImageExistsForURL:(nullable NSURL *)url;
|
||||
|
||||
/**
|
||||
* Async check if image has already been cached
|
||||
*
|
||||
|
|
|
@ -66,17 +66,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)cachedImageExistsForURL:(nullable NSURL *)url {
|
||||
NSString *key = [self cacheKeyForURL:url];
|
||||
if ([self.imageCache imageFromMemoryCacheForKey:key] != nil) return YES;
|
||||
return [self.imageCache diskImageExistsWithKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)diskImageExistsForURL:(nullable NSURL *)url {
|
||||
NSString *key = [self cacheKeyForURL:url];
|
||||
return [self.imageCache diskImageExistsWithKey:key];
|
||||
}
|
||||
|
||||
- (void)cachedImageExistsForURL:(nullable NSURL *)url
|
||||
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
|
||||
NSString *key = [self cacheKeyForURL:url];
|
||||
|
@ -154,7 +143,7 @@
|
|||
}
|
||||
NSString *key = [self cacheKeyForURL:url];
|
||||
|
||||
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
|
||||
operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
|
||||
if (operation.isCancelled) {
|
||||
@synchronized (self.runningOperations) {
|
||||
[self.runningOperations removeObject:operation];
|
||||
|
@ -229,7 +218,8 @@
|
|||
|
||||
if (transformedImage && finished) {
|
||||
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
|
||||
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : downloadedData) forKey:key toDisk:cacheOnDisk];
|
||||
// pass nil if the image was transformed, so we can recalculate the data from the image
|
||||
[self.imageCache storeImage:transformedImage imageData:(imageWasTransformed ? nil : downloadedData) forKey:key toDisk:cacheOnDisk completion:nil];
|
||||
}
|
||||
|
||||
dispatch_main_sync_safe(^{
|
||||
|
@ -240,7 +230,7 @@
|
|||
});
|
||||
} else {
|
||||
if (downloadedImage && finished) {
|
||||
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:downloadedData forKey:key toDisk:cacheOnDisk];
|
||||
[self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];
|
||||
}
|
||||
|
||||
dispatch_main_sync_safe(^{
|
||||
|
@ -299,7 +289,7 @@
|
|||
- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url {
|
||||
if (image && url) {
|
||||
NSString *key = [self cacheKeyForURL:url];
|
||||
[self.imageCache storeImage:image forKey:key toDisk:YES];
|
||||
[self.imageCache storeImage:image forKey:key toDisk:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
*/
|
||||
|
||||
#import "SDWebImageCompat.h"
|
||||
#import "NSData+ImageContentType.h"
|
||||
|
||||
@interface UIImage (MultiFormat)
|
||||
|
||||
+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data;
|
||||
- (nullable NSData *)sd_imageData;
|
||||
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat;
|
||||
|
||||
@end
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
}
|
||||
|
||||
UIImage *image;
|
||||
NSString *imageContentType = [NSData sd_contentTypeForImageData:data];
|
||||
if ([imageContentType isEqualToString:@"image/gif"]) {
|
||||
SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
|
||||
if (imageFormat == SDImageFormatGIF) {
|
||||
image = [UIImage sd_animatedGIFWithData:data];
|
||||
}
|
||||
#ifdef SD_WEBP
|
||||
else if ([imageContentType isEqualToString:@"image/webp"])
|
||||
else if (imageFormat == SDImageFormatWebP)
|
||||
{
|
||||
image = [UIImage sd_imageWithWebPData:data];
|
||||
}
|
||||
|
@ -116,5 +116,46 @@
|
|||
}
|
||||
#endif
|
||||
|
||||
- (nullable NSData *)sd_imageData {
|
||||
return [self sd_imageDataAsFormat:SDImageFormatUndefined];
|
||||
}
|
||||
|
||||
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
|
||||
NSData *imageData = nil;
|
||||
if (self) {
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
int alphaInfo = CGImageGetAlphaInfo(self.CGImage);
|
||||
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
|
||||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
|
||||
alphaInfo == kCGImageAlphaNoneSkipLast);
|
||||
|
||||
BOOL usePNG = hasAlpha;
|
||||
|
||||
// the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel
|
||||
if (imageFormat != SDImageFormatUndefined) {
|
||||
usePNG = (imageFormat == SDImageFormatPNG);
|
||||
}
|
||||
|
||||
if (usePNG) {
|
||||
imageData = UIImagePNGRepresentation(self);
|
||||
} else {
|
||||
imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0);
|
||||
}
|
||||
#else
|
||||
NSBitmapImageFileType imageFileType = NSJPEGFileType;
|
||||
if (imageFormat == SDImageFormatGIF) {
|
||||
imageFileType = NSGIFFileType;
|
||||
} else if (imageFormat == SDImageFormatPNG) {
|
||||
imageFileType = NSPNGFileType;
|
||||
}
|
||||
|
||||
imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations
|
||||
usingType:imageFileType
|
||||
properties:@{}];
|
||||
#endif
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -88,11 +88,6 @@
|
|||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock;
|
||||
|
||||
/**
|
||||
* Cancel the current download
|
||||
*/
|
||||
- (void)sd_cancelCurrentHighlightedImageLoad;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -118,16 +60,15 @@ static char TAG_ACTIVITY_SHOW;
|
|||
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDExternalCompletionBlock)completedBlock {
|
||||
NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url];
|
||||
UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key];
|
||||
UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:key];
|
||||
|
||||
[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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* 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);
|
||||
return;
|
||||
}
|
||||
#if SD_UIKIT
|
||||
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];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (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
|
|
@ -1,11 +1,15 @@
|
|||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
|
||||
use_frameworks!
|
||||
|
||||
xcodeproj 'SDWebImage Tests'
|
||||
workspace '../SDWebImage'
|
||||
|
||||
target 'Tests' do
|
||||
platform :ios, '7.0'
|
||||
pod 'Expecta', '<=0.3.1'
|
||||
pod 'SDWebImage', :path => '../'
|
||||
platform :ios, '8.0'
|
||||
pod 'Expecta'
|
||||
pod 'SDWebImage/WebP', :path => '../'
|
||||
pod 'SDWebImage/MapKit', :path => '../'
|
||||
pod 'SDWebImage/GIF', :path => '../'
|
||||
|
||||
end
|
||||
|
|
|
@ -7,8 +7,14 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0D87E1F83BD319CEC7622E9F /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0462A7F023A057322E59B3C5 /* libPods-Tests.a */; };
|
||||
1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; };
|
||||
433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */; };
|
||||
433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB61D7EF8200086B6E9 /* TestImage.gif */; };
|
||||
433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBB81D7EF8260086B6E9 /* TestImage.png */; };
|
||||
433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */; };
|
||||
4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; };
|
||||
4369C2741D9804B1007E863A /* SDCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDCategoriesTests.m */; };
|
||||
53F0240D24D359127872F512 /* Pods_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */; };
|
||||
5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */; };
|
||||
DA248D57195472AA00390AB0 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA248D56195472AA00390AB0 /* XCTest.framework */; };
|
||||
DA248D59195472AA00390AB0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA248D58195472AA00390AB0 /* Foundation.framework */; };
|
||||
|
@ -20,8 +26,14 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0462A7F023A057322E59B3C5 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderTests.m; sourceTree = "<group>"; };
|
||||
433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDecoderTests.m; sourceTree = "<group>"; };
|
||||
433BBBB61D7EF8200086B6E9 /* TestImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = TestImage.gif; sourceTree = "<group>"; };
|
||||
433BBBB81D7EF8260086B6E9 /* TestImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImage.png; sourceTree = "<group>"; };
|
||||
433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = MonochromeTestImage.jpg; sourceTree = "<group>"; };
|
||||
4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImagePrefetcherTests.m; sourceTree = "<group>"; };
|
||||
4369C2731D9804B1007E863A /* SDCategoriesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = "<group>"; };
|
||||
5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = TestImage.jpg; sourceTree = "<group>"; };
|
||||
700B00151041D7EE118B1ABD /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A0085854E7D88C98F2F6C9FC /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
|
@ -45,7 +57,7 @@
|
|||
DA248D57195472AA00390AB0 /* XCTest.framework in Frameworks */,
|
||||
DA248D5B195472AA00390AB0 /* UIKit.framework in Frameworks */,
|
||||
DA248D59195472AA00390AB0 /* Foundation.framework in Frameworks */,
|
||||
0D87E1F83BD319CEC7622E9F /* libPods-Tests.a in Frameworks */,
|
||||
53F0240D24D359127872F512 /* Pods_Tests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -85,7 +97,7 @@
|
|||
DA248D56195472AA00390AB0 /* XCTest.framework */,
|
||||
DA248D58195472AA00390AB0 /* Foundation.framework */,
|
||||
DA248D5A195472AA00390AB0 /* UIKit.framework */,
|
||||
0462A7F023A057322E59B3C5 /* libPods-Tests.a */,
|
||||
1DAAA77E3CA7387F702040D9 /* Pods_Tests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -93,12 +105,18 @@
|
|||
DA248D5C195472AA00390AB0 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */,
|
||||
433BBBB61D7EF8200086B6E9 /* TestImage.gif */,
|
||||
5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */,
|
||||
433BBBB81D7EF8260086B6E9 /* TestImage.png */,
|
||||
DA248D5D195472AA00390AB0 /* Supporting Files */,
|
||||
DA248D68195475D800390AB0 /* SDImageCacheTests.m */,
|
||||
DA248D6A195476AC00390AB0 /* SDWebImageManagerTests.m */,
|
||||
DA91BEBB19795BC9006F2536 /* UIImageMultiFormatTests.m */,
|
||||
1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */,
|
||||
433BBBB41D7EF5C00086B6E9 /* SDWebImageDecoderTests.m */,
|
||||
4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */,
|
||||
4369C2731D9804B1007E863A /* SDCategoriesTests.m */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -120,12 +138,12 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DA248D67195472AA00390AB0 /* Build configuration list for PBXNativeTarget "Tests" */;
|
||||
buildPhases = (
|
||||
09522B7196293172D6408744 /* 📦 Check Pods Manifest.lock */,
|
||||
09522B7196293172D6408744 /* [CP] Check Pods Manifest.lock */,
|
||||
DA248D4F195472AA00390AB0 /* Sources */,
|
||||
DA248D50195472AA00390AB0 /* Frameworks */,
|
||||
DA248D51195472AA00390AB0 /* Resources */,
|
||||
C86216497B5A0BA9501E2C07 /* 📦 Embed Pods Frameworks */,
|
||||
85E5D3885A03BFC23B050908 /* 📦 Copy Pods Resources */,
|
||||
C86216497B5A0BA9501E2C07 /* [CP] Embed Pods Frameworks */,
|
||||
85E5D3885A03BFC23B050908 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -167,36 +185,39 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */,
|
||||
433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */,
|
||||
DA248D61195472AA00390AB0 /* InfoPlist.strings in Resources */,
|
||||
433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */,
|
||||
433BBBBB1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
09522B7196293172D6408744 /* 📦 Check Pods Manifest.lock */ = {
|
||||
09522B7196293172D6408744 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
85E5D3885A03BFC23B050908 /* 📦 Copy Pods Resources */ = {
|
||||
85E5D3885A03BFC23B050908 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -204,14 +225,14 @@
|
|||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C86216497B5A0BA9501E2C07 /* 📦 Embed Pods Frameworks */ = {
|
||||
C86216497B5A0BA9501E2C07 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Embed Pods Frameworks";
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -227,8 +248,11 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1E3C51E919B46E370092B5E6 /* SDWebImageDownloaderTests.m in Sources */,
|
||||
4369C2741D9804B1007E863A /* SDCategoriesTests.m in Sources */,
|
||||
4369C1D11D97F80F007E863A /* SDWebImagePrefetcherTests.m in Sources */,
|
||||
DA248D69195475D800390AB0 /* SDImageCacheTests.m in Sources */,
|
||||
DA248D6B195476AC00390AB0 /* SDWebImageManagerTests.m in Sources */,
|
||||
433BBBB51D7EF5C00086B6E9 /* SDWebImageDecoderTests.m in Sources */,
|
||||
DA91BEBC19795BC9006F2536 /* UIImageMultiFormatTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -251,7 +275,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ENABLE_TESTABILITY = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -259,7 +283,7 @@
|
|||
DA248D4B1954721A00390AB0 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#define EXP_SHORTHAND // required by Expecta
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import <SDWebImage/UIImageView+WebCache.h>
|
||||
#import <SDWebImage/UIImageView+HighlightedWebCache.h>
|
||||
#import <SDWebImage/MKAnnotationView+WebCache.h>
|
||||
#import <SDWebImage/UIButton+WebCache.h>
|
||||
#import <SDWebImage/FLAnimatedImageView+WebCache.h>
|
||||
|
||||
@import FLAnimatedImage;
|
||||
|
||||
@interface SDCategoriesTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDCategoriesTests
|
||||
|
||||
- (void)testUIImageViewSetImageWithURL {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setImageWithURL"];
|
||||
|
||||
UIImageView *imageView = [[UIImageView alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage050.jpg"];
|
||||
[imageView sd_setImageWithURL:originalImageURL
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect(imageView.image).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testUIImageViewSetHighlightedImageWithURL {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"UIImageView setHighlightedImageWithURL"];
|
||||
|
||||
UIImageView *imageView = [[UIImageView alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage051.jpg"];
|
||||
[imageView sd_setHighlightedImageWithURL:originalImageURL
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect(imageView.highlightedImage).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testMKAnnotationViewSetImageWithURL {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"MKAnnotationView setImageWithURL"];
|
||||
|
||||
MKAnnotationView *annotationView = [[MKAnnotationView alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage052.jpg"];
|
||||
[annotationView sd_setImageWithURL:originalImageURL
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect(annotationView.image).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testUIButtonSetImageWithURLNormalState {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL normalState"];
|
||||
|
||||
UIButton *button = [[UIButton alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage053.jpg"];
|
||||
[button sd_setImageWithURL:originalImageURL
|
||||
forState:UIControlStateNormal
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect([button imageForState:UIControlStateNormal]).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testUIButtonSetImageWithURLHighlightedState {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setImageWithURL highlightedState"];
|
||||
|
||||
UIButton *button = [[UIButton alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage054.jpg"];
|
||||
[button sd_setImageWithURL:originalImageURL
|
||||
forState:UIControlStateHighlighted
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect([button imageForState:UIControlStateHighlighted]).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testUIButtonSetBackgroundImageWithURLNormalState {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"UIButton setBackgroundImageWithURL normalState"];
|
||||
|
||||
UIButton *button = [[UIButton alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage055.jpg"];
|
||||
[button sd_setBackgroundImageWithURL:originalImageURL
|
||||
forState:UIControlStateNormal
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
expect([button backgroundImageForState:UIControlStateNormal]).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testFLAnimatedImageViewSetImageWithURL {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"FLAnimatedImageView setImageWithURL"];
|
||||
|
||||
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"];
|
||||
|
||||
[imageView sd_setImageWithURL:originalImageURL
|
||||
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
expect(image).toNot.beNil();
|
||||
expect(error).to.beNil();
|
||||
expect(originalImageURL).to.equal(imageURL);
|
||||
|
||||
expect(imageView.image).to.equal(image);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
@end
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import "SDImageCache.h"
|
||||
#import <SDWebImage/SDImageCache.h>
|
||||
|
||||
NSString *kImageTestKey = @"TestImageKey.jpg";
|
||||
|
||||
|
@ -22,172 +22,179 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
|
|||
|
||||
@implementation SDImageCacheTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
self.sharedImageCache = [SDImageCache sharedImageCache];
|
||||
[self clearAllCaches];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testSharedImageCache {
|
||||
- (void)test01SharedImageCache {
|
||||
expect(self.sharedImageCache).toNot.beNil();
|
||||
}
|
||||
|
||||
- (void)testSingleton{
|
||||
- (void)test02Singleton{
|
||||
expect(self.sharedImageCache).to.equal([SDImageCache sharedImageCache]);
|
||||
}
|
||||
|
||||
- (void)testClearDiskCache{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
[self.sharedImageCache clearDiskOnCompletion:^{
|
||||
expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(NO);
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]);
|
||||
}];
|
||||
- (void)test03ImageCacheCanBeInstantiated {
|
||||
SDImageCache *imageCache = [[SDImageCache alloc] init];
|
||||
expect(imageCache).toNot.equal([SDImageCache sharedImageCache]);
|
||||
}
|
||||
|
||||
- (void)testClearMemoryCache{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test04ClearDiskCache{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Clear disk cache"];
|
||||
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
[self.sharedImageCache clearDiskOnCompletion:^{
|
||||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
if (!isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should not be in cache");
|
||||
}
|
||||
}];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]);
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test05ClearMemoryCache{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Clear memory cache"];
|
||||
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
[self.sharedImageCache clearMemory];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
// Seems not able to access the files correctly (maybe only from test?)
|
||||
//expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(YES);
|
||||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
expect(isInCache).to.equal(YES);
|
||||
if (isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should be in cache");
|
||||
}
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
// Testing storeImage:forKey:
|
||||
- (void)testInsertionOfImage {
|
||||
- (void)test06InsertionOfImage {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey"];
|
||||
|
||||
UIImage *image = [self imageForTesting];
|
||||
[self.sharedImageCache storeImage:image forKey:kImageTestKey];
|
||||
[self.sharedImageCache storeImage:image forKey:kImageTestKey completion:nil];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image);
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.equal(image);
|
||||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
if (isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should be in cache");
|
||||
}
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
// Testing storeImage:forKey:toDisk:YES
|
||||
- (void)testInsertionOfImageForcingDiskStorage{
|
||||
- (void)test07InsertionOfImageForcingDiskStorage{
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=YES"];
|
||||
|
||||
UIImage *image = [self imageForTesting];
|
||||
[self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:YES];
|
||||
[self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:YES completion:nil];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image);
|
||||
// Seems not able to access the files correctly (maybe only from test?)
|
||||
//expect([self.sharedImageCache diskImageExistsWithKey:kImageTestKey]).to.equal(YES);
|
||||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
expect(isInCache).to.equal(YES);
|
||||
if (isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should be in cache");
|
||||
}
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
// Testing storeImage:forKey:toDisk:NO
|
||||
- (void)testInsertionOfImageOnlyInMemory {
|
||||
- (void)test08InsertionOfImageOnlyInMemory {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=NO"];
|
||||
UIImage *image = [self imageForTesting];
|
||||
[self.sharedImageCache storeImage:image forKey:@"TestImage" toDisk:NO];
|
||||
[self.sharedImageCache diskImageExistsWithKey:@"TestImage" completion:^(BOOL isInCache) {
|
||||
expect(isInCache).to.equal(YES);
|
||||
[self.sharedImageCache storeImage:image forKey:kImageTestKey toDisk:NO completion:nil];
|
||||
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]);
|
||||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
if (!isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should not be in cache");
|
||||
}
|
||||
}];
|
||||
[self.sharedImageCache clearMemory];
|
||||
[self.sharedImageCache diskImageExistsWithKey:@"TestImage" completion:^(BOOL isInCache) {
|
||||
expect(isInCache).to.equal(NO);
|
||||
}];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil();
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testRetrievalImageThroughNSOperation{
|
||||
//- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
|
||||
- (void)test09RetrieveImageThroughNSOperation{
|
||||
//- (NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
|
||||
UIImage *imageForTesting = [self imageForTesting];
|
||||
[self.sharedImageCache storeImage:imageForTesting forKey:kImageTestKey];
|
||||
NSOperation *operation = [self.sharedImageCache queryDiskCacheForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
|
||||
[self.sharedImageCache storeImage:imageForTesting forKey:kImageTestKey completion:nil];
|
||||
NSOperation *operation = [self.sharedImageCache queryCacheOperationForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
|
||||
expect(image).to.equal(imageForTesting);
|
||||
}];
|
||||
expect(operation).toNot.beNil;
|
||||
}
|
||||
|
||||
- (void)testRemoveImageForKey{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey];
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
|
||||
}
|
||||
|
||||
- (void)testRemoveImageForKeyWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test10RemoveImageForKeyWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey withCompletion:^{
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testRemoveImageForKeyNotFromDisk{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO];
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil;
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
}
|
||||
|
||||
- (void)testRemoveImageForKeyFromDisk{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO];
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
}
|
||||
|
||||
- (void)testRemoveImageforKeyNotFromDiskWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test11RemoveImageforKeyNotFromDiskWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:NO withCompletion:^{
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil;
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testRemoveImageforKeyFromDiskWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test12RemoveImageforKeyFromDiskWithCompletion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
[self.sharedImageCache removeImageForKey:kImageTestKey fromDisk:YES withCompletion:^{
|
||||
expect([self.sharedImageCache imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
|
||||
expect([self.sharedImageCache imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
|
||||
}];
|
||||
}
|
||||
|
||||
// TODO -- Testing insertion with recalculate
|
||||
- (void)testInsertionOfImageOnlyInDisk {
|
||||
}
|
||||
|
||||
- (void)testInitialCacheSize{
|
||||
- (void)test20InitialCacheSize{
|
||||
expect([self.sharedImageCache getSize]).to.equal(0);
|
||||
}
|
||||
|
||||
- (void)testInitialDiskCount{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test21InitialDiskCount{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
expect([self.sharedImageCache getDiskCount]).to.equal(1);
|
||||
}
|
||||
|
||||
- (void)testDiskCountAfterInsertion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test22DiskCountAfterInsertion{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
expect([self.sharedImageCache getDiskCount]).to.equal(1);
|
||||
}
|
||||
|
||||
- (void)testDefaultCachePathForAnyKey{
|
||||
- (void)test31DefaultCachePathForAnyKey{
|
||||
NSString *path = [self.sharedImageCache defaultCachePathForKey:kImageTestKey];
|
||||
expect(path).toNot.beNil;
|
||||
}
|
||||
|
||||
- (void)testCachePathForNonExistingKey{
|
||||
- (void)test32CachePathForNonExistingKey{
|
||||
NSString *path = [self.sharedImageCache cachePathForKey:kImageTestKey inPath:[self.sharedImageCache defaultCachePathForKey:kImageTestKey]];
|
||||
expect(path).to.beNil;
|
||||
}
|
||||
|
||||
- (void)testCachePathForExistingKey{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey];
|
||||
- (void)test33CachePathForExistingKey{
|
||||
[self.sharedImageCache storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
|
||||
NSString *path = [self.sharedImageCache cachePathForKey:kImageTestKey inPath:[self.sharedImageCache defaultCachePathForKey:kImageTestKey]];
|
||||
expect(path).notTo.beNil;
|
||||
}
|
||||
|
||||
// TODO -- Testing image data insertion
|
||||
|
||||
- (void)testInsertionOfImageData {
|
||||
- (void)test40InsertionOfImageData {
|
||||
|
||||
NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]];
|
||||
[self.sharedImageCache storeImageDataToDisk:imageData forKey:kImageTestKey];
|
||||
|
@ -202,18 +209,28 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
|
|||
[self.sharedImageCache diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
|
||||
expect(isInCache).to.equal(YES);
|
||||
}];
|
||||
|
||||
[self.sharedImageCache calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
|
||||
expect(fileCount).to.beLessThan(100);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark Helper methods
|
||||
|
||||
- (void)clearAllCaches{
|
||||
[self.sharedImageCache clearDisk];
|
||||
[self.sharedImageCache deleteOldFilesWithCompletionBlock:nil];
|
||||
|
||||
// TODO: this is not ok, clearDiskOnCompletion will clear async, this means that when we execute the tests, the cache might not be cleared
|
||||
[self.sharedImageCache clearDiskOnCompletion:nil];
|
||||
[self.sharedImageCache clearMemory];
|
||||
}
|
||||
|
||||
- (UIImage *)imageForTesting{
|
||||
|
||||
return [UIImage imageWithContentsOfFile:[self testImagePath]];
|
||||
static UIImage *reusableImage = nil;
|
||||
if (!reusableImage) {
|
||||
reusableImage = [UIImage imageWithContentsOfFile:[self testImagePath]];
|
||||
}
|
||||
return reusableImage;
|
||||
}
|
||||
|
||||
- (NSString *)testImagePath {
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#define EXP_SHORTHAND // required by Expecta
|
||||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
#import <SDWebImage/SDWebImageDecoder.h>
|
||||
|
||||
@interface SDWebImageDecoderTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImageDecoderTests
|
||||
|
||||
- (void)test01ThatDecodedImageWithNilImageReturnsNil {
|
||||
expect([UIImage decodedImageWithImage:nil]).to.beNil();
|
||||
}
|
||||
|
||||
- (void)test02ThatDecodedImageWithImageWorksWithARegularJPGImage {
|
||||
NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"jpg"];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:testImagePath];
|
||||
UIImage *decodedImage = [UIImage decodedImageWithImage:image];
|
||||
expect(decodedImage).toNot.beNil();
|
||||
expect(decodedImage).toNot.equal(image);
|
||||
}
|
||||
|
||||
- (void)test03ThatDecodedImageWithImageDoesNotDecodeAnimatedImages {
|
||||
NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"gif"];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:testImagePath];
|
||||
UIImage *animatedImage = [UIImage animatedImageWithImages:@[image] duration:0];
|
||||
UIImage *decodedImage = [UIImage decodedImageWithImage:animatedImage];
|
||||
expect(decodedImage).toNot.beNil();
|
||||
expect(decodedImage).to.equal(animatedImage);
|
||||
}
|
||||
|
||||
- (void)test04ThatDecodedImageWithImageDoesNotDecodeImagesWithAlpha {
|
||||
NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestImage" ofType:@"png"];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:testImagePath];
|
||||
UIImage *decodedImage = [UIImage decodedImageWithImage:image];
|
||||
expect(decodedImage).toNot.beNil();
|
||||
expect(decodedImage).to.equal(image);
|
||||
}
|
||||
|
||||
- (void)test05ThatDecodedImageWithImageWorksEvenWithMonochromeImage {
|
||||
NSString * testImagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"MonochromeTestImage" ofType:@"jpg"];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:testImagePath];
|
||||
UIImage *decodedImage = [UIImage decodedImageWithImage:image];
|
||||
expect(decodedImage).toNot.beNil();
|
||||
expect(decodedImage).toNot.equal(image);
|
||||
}
|
||||
|
||||
@end
|
|
@ -11,9 +11,49 @@
|
|||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import <SDWebImage/SDWebImageDownloader.h>
|
||||
#import <SDWebImage/SDWebImageDownloaderOperation.h>
|
||||
|
||||
/**
|
||||
* Category for SDWebImageDownloader so we can access the operationClass
|
||||
*/
|
||||
@interface SDWebImageDownloader ()
|
||||
@property (assign, nonatomic, nullable) Class operationClass;
|
||||
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;
|
||||
|
||||
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
|
||||
forURL:(nullable NSURL *)url
|
||||
createCallback:(SDWebImageDownloaderOperation *(^)())createCallback;
|
||||
@end
|
||||
|
||||
/**
|
||||
* A class that fits the NSOperation+SDWebImageDownloaderOperationInterface requirement so we can test
|
||||
*/
|
||||
@interface CustomDownloaderOperation : NSOperation<SDWebImageDownloaderOperationInterface>
|
||||
|
||||
@property (nonatomic, assign) BOOL shouldDecompressImages;
|
||||
@property (nonatomic, strong, nullable) NSURLCredential *credential;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CustomDownloaderOperation
|
||||
|
||||
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)req inSession:(nullable NSURLSession *)ses options:(SDWebImageDownloaderOptions)opt {
|
||||
if ((self = [super init])) { }
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
|
||||
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#import "SDWebImageDownloader.h"
|
||||
|
||||
@interface SDWebImageDownloaderTests : XCTestCase
|
||||
|
||||
|
@ -21,68 +61,288 @@
|
|||
|
||||
@implementation SDWebImageDownloaderTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
- (void)test01ThatSharedDownloaderIsNotEqualToInitDownloader {
|
||||
SDWebImageDownloader *downloader = [[SDWebImageDownloader alloc] init];
|
||||
expect(downloader).toNot.equal([SDWebImageDownloader sharedDownloader]);
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
- (void)test02ThatByDefaultDownloaderSetsTheAcceptHTTPHeader {
|
||||
expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:@"Accept"]).to.match(@"image/\\*");
|
||||
}
|
||||
|
||||
- (void)testThatDownloadingSameURLTwiceAndCancellingFirstWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"];
|
||||
|
||||
id token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
XCTFail(@"Shouldn't have completed here.");
|
||||
}];
|
||||
expect(token1).toNot.beNil();
|
||||
|
||||
id token2 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
[expectation fulfill];
|
||||
}];
|
||||
expect(token2).toNot.beNil();
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] cancel:token1];
|
||||
|
||||
[self waitForExpectationsWithTimeout:5. handler:nil];
|
||||
- (void)test03ThatSetAndGetValueForHTTPHeaderFieldWork {
|
||||
NSString *headerValue = @"Tests";
|
||||
NSString *headerName = @"AppName";
|
||||
// set it
|
||||
[[SDWebImageDownloader sharedDownloader] setValue:headerValue forHTTPHeaderField:headerName];
|
||||
expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:headerName]).to.equal(headerValue);
|
||||
// clear it
|
||||
[[SDWebImageDownloader sharedDownloader] setValue:nil forHTTPHeaderField:headerName];
|
||||
expect([[SDWebImageDownloader sharedDownloader] valueForHTTPHeaderField:headerName]).to.beNil();
|
||||
}
|
||||
|
||||
- (void)testThatCancelingDownloadThenRequestingAgainWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"];
|
||||
- (void)test04ThatASimpleDownloadWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage004.jpg"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test05ThatSetAndGetMaxConcurrentDownloadsWorks {
|
||||
NSInteger initialValue = [SDWebImageDownloader sharedDownloader].maxConcurrentDownloads;
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:3];
|
||||
expect([SDWebImageDownloader sharedDownloader].maxConcurrentDownloads).to.equal(3);
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] setMaxConcurrentDownloads:initialValue];
|
||||
}
|
||||
|
||||
- (void)test06ThatUsingACustomDownloaderOperationWorks {
|
||||
// we try to set a usual NSOperation as operation class. Should not work
|
||||
[[SDWebImageDownloader sharedDownloader] setOperationClass:[NSOperation class]];
|
||||
expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]);
|
||||
|
||||
// setting an NSOperation subclass that conforms to SDWebImageDownloaderOperationInterface - should work
|
||||
[[SDWebImageDownloader sharedDownloader] setOperationClass:[CustomDownloaderOperation class]];
|
||||
expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([CustomDownloaderOperation class]);
|
||||
|
||||
// back to the original value
|
||||
[[SDWebImageDownloader sharedDownloader] setOperationClass:nil];
|
||||
expect([SDWebImageDownloader sharedDownloader].operationClass).to.equal([SDWebImageDownloaderOperation class]);
|
||||
}
|
||||
|
||||
- (void)test07ThatAddProgressCallbackCompletedBlockWithNilURLCallsTheCompletionBlockWithNils {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with nils"];
|
||||
[[SDWebImageDownloader sharedDownloader] addProgressCallback:nil completedBlock:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (!image && !data && !error) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"All params should be nil");
|
||||
}
|
||||
} forURL:nil createCallback:nil];
|
||||
[self waitForExpectationsWithTimeout:0.5 handler:nil];
|
||||
}
|
||||
|
||||
- (void)test08ThatAHTTPAuthDownloadWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP Auth download"];
|
||||
[SDWebImageDownloader sharedDownloader].username = @"httpwatch";
|
||||
[SDWebImageDownloader sharedDownloader].password = @"httpwatch01";
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
[SDWebImageDownloader sharedDownloader].username = nil;
|
||||
[SDWebImageDownloader sharedDownloader].password = nil;
|
||||
}
|
||||
|
||||
- (void)test09ThatProgressiveJPEGWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive JPEG download"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage009.jpg"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveDownload progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else if (finished) {
|
||||
XCTFail(@"Something went wrong");
|
||||
} else {
|
||||
// progressive updates
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test10That404CaseCallsCompletionWithError {
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://static2.dmcdn.net/static/video/656/177/44771656:jpeg_preview_small.jpg?20120509154705"];
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"404"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (!image && !data && error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
id token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
XCTFail(@"Shouldn't have completed here.");
|
||||
}];
|
||||
- (void)test11ThatCancelWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage011.jpg"];
|
||||
SDWebImageDownloadToken *token = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
XCTFail(@"Should not get here");
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] cancel:token];
|
||||
|
||||
// doesn't cancel immediately - since it uses dispatch async
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(0);
|
||||
[expectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test12ThatWeCanUseAnotherSessionForEachDownloadOperation {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Owned session"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage012.jpg"];
|
||||
|
||||
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
|
||||
request.HTTPShouldUsePipelining = YES;
|
||||
request.allHTTPHeaderFields = @{@"Accept": @"image/*;q=0.8"};
|
||||
|
||||
SDWebImageDownloaderOperation *operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request
|
||||
inSession:nil
|
||||
options:0];
|
||||
[operation addHandlersForProgress:^(NSInteger receivedSize, NSInteger expectedSize) {
|
||||
|
||||
} completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
|
||||
[operation start];
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test13ThatDownloadCanContinueWhenTheAppEntersBackground {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Simple download"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage013.jpg"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderContinueInBackground progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test14ThatPNGWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test15ThatWEBPWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"];
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"];
|
||||
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect([SDWebImageDownloader sharedDownloader].currentDownloadCount).to.equal(1);
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
/**
|
||||
* Per #883 - Fix multiple requests for same image and then canceling one
|
||||
* Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel
|
||||
* In 4.0, via #883 added `SDWebImageDownloadToken` so we can cancel exactly the request we want
|
||||
* This test validates the scenario of making 2 requests for the same image and cancelling the 1st one
|
||||
*/
|
||||
- (void)test20ThatDownloadingSameURLTwiceAndCancellingFirstWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage020.jpg"];
|
||||
|
||||
SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
XCTFail(@"Shouldn't have completed here.");
|
||||
}];
|
||||
expect(token1).toNot.beNil();
|
||||
|
||||
SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect(token2).toNot.beNil();
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] cancel:token1];
|
||||
|
||||
id token2 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
[expectation fulfill];
|
||||
}];
|
||||
expect(token2).toNot.beNil();
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
[self waitForExpectationsWithTimeout:5. handler:nil];
|
||||
/**
|
||||
* Per #883 - Fix multiple requests for same image and then canceling one
|
||||
* Old SDWebImage (3.x) could not handle correctly multiple requests for the same image + cancel
|
||||
* In 4.0, via #883 added `SDWebImageDownloadToken` so we can cancel exactly the request we want
|
||||
* This test validates the scenario of requesting an image, cancel and then requesting it again
|
||||
*/
|
||||
- (void)test21ThatCancelingDownloadThenRequestingAgainWorks {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage021.jpg"];
|
||||
|
||||
SDWebImageDownloadToken *token1 = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
XCTFail(@"Shouldn't have completed here.");
|
||||
}];
|
||||
expect(token1).toNot.beNil();
|
||||
|
||||
[[SDWebImageDownloader sharedDownloader] cancel:token1];
|
||||
|
||||
SDWebImageDownloadToken *token2 = [[SDWebImageDownloader sharedDownloader]
|
||||
downloadImageWithURL:imageURL
|
||||
options:0
|
||||
progress:nil
|
||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||
if (image && data && !error && finished) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
NSLog(@"image = %@, data = %@, error = %@", image, data, error);
|
||||
XCTFail(@"Something went wrong");
|
||||
}
|
||||
}];
|
||||
expect(token2).toNot.beNil();
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,12 +10,11 @@
|
|||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import "SDWebImageManager.h"
|
||||
|
||||
static int64_t kAsyncTestTimeout = 5;
|
||||
#import <SDWebImage/SDWebImageManager.h>
|
||||
|
||||
NSString *workingImageURL = @"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg";
|
||||
|
||||
@interface SDWebImageManagerTests : XCTestCase
|
||||
|
||||
|
@ -23,22 +22,15 @@ static int64_t kAsyncTestTimeout = 5;
|
|||
|
||||
@implementation SDWebImageManagerTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
- (void)test01ThatSharedManagerIsNotEqualToInitManager {
|
||||
SDWebImageManager *manager = [[SDWebImageManager alloc] init];
|
||||
expect(manager).toNot.equal([SDWebImageManager sharedManager]);
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testThatDownloadInvokesCompletionBlockWithCorrectParamsAsync {
|
||||
- (void)test02ThatDownloadInvokesCompletionBlockWithCorrectParamsAsync {
|
||||
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image download completes"];
|
||||
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"];
|
||||
NSURL *originalImageURL = [NSURL URLWithString:workingImageURL];
|
||||
|
||||
[[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL
|
||||
options:SDWebImageRefreshCached
|
||||
|
@ -51,11 +43,12 @@ static int64_t kAsyncTestTimeout = 5;
|
|||
[expectation fulfill];
|
||||
expectation = nil;
|
||||
}];
|
||||
expect([[SDWebImageManager sharedManager] isRunning]).to.equal(YES);
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)testThatDownloadWithIncorrectURLInvokesCompletionBlockWithAnErrorAsync {
|
||||
- (void)test03ThatDownloadWithIncorrectURLInvokesCompletionBlockWithAnErrorAsync {
|
||||
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image download completes"];
|
||||
|
||||
NSURL *originalImageURL = [NSURL URLWithString:@"http://static2.dmcdn.net/static/video/656/177/44771656:jpeg_preview_small.png"];
|
||||
|
@ -75,4 +68,49 @@ static int64_t kAsyncTestTimeout = 5;
|
|||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test04CachedImageExistsForURL {
|
||||
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in cache"];
|
||||
NSURL *imageURL = [NSURL URLWithString:workingImageURL];
|
||||
[[SDWebImageManager sharedManager] cachedImageExistsForURL:imageURL completion:^(BOOL isInCache) {
|
||||
if (isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should be in cache");
|
||||
}
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test05DiskImageExistsForURL {
|
||||
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in disk cache"];
|
||||
NSURL *imageURL = [NSURL URLWithString:workingImageURL];
|
||||
[[SDWebImageManager sharedManager] diskImageExistsForURL:imageURL completion:^(BOOL isInCache) {
|
||||
if (isInCache) {
|
||||
[expectation fulfill];
|
||||
} else {
|
||||
XCTFail(@"Image should be in cache");
|
||||
}
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test06CancellAll {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"];
|
||||
|
||||
NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage006.jpg"];
|
||||
[[SDWebImageManager sharedManager] loadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
XCTFail(@"Should not get here");
|
||||
}];
|
||||
|
||||
[[SDWebImageManager sharedManager] cancelAll];
|
||||
|
||||
// doesn't cancel immediately - since it uses dispatch async
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
expect([[SDWebImageManager sharedManager] isRunning]).to.equal(NO);
|
||||
[expectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
* (c) Matt Galloway
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#define EXP_SHORTHAND // required by Expecta
|
||||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import <SDWebImage/SDWebImagePrefetcher.h>
|
||||
|
||||
@interface SDWebImagePrefetcherTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDWebImagePrefetcherTests
|
||||
|
||||
- (void)test01ThatSharedPrefetcherIsNotEqualToInitPrefetcher {
|
||||
SDWebImagePrefetcher *prefetcher = [[SDWebImagePrefetcher alloc] init];
|
||||
expect(prefetcher).toNot.equal([SDWebImagePrefetcher sharedImagePrefetcher]);
|
||||
}
|
||||
|
||||
- (void)test02PrefetchMultipleImages {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Correct prefetch of multiple images"];
|
||||
|
||||
NSMutableArray *imageURLs = [NSMutableArray array];
|
||||
|
||||
for (int i=40; i<43; i++) {
|
||||
NSString *imageURLString = [NSString stringWithFormat:@"https://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage%03d.jpg", i];
|
||||
NSURL *imageURL = [NSURL URLWithString:imageURLString];
|
||||
[imageURLs addObject:imageURL];
|
||||
}
|
||||
|
||||
__block int numberOfPrefetched = 0;
|
||||
|
||||
[[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs progress:^(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls) {
|
||||
numberOfPrefetched += 1;
|
||||
expect(numberOfPrefetched).to.equal(noOfFinishedUrls);
|
||||
expect(noOfFinishedUrls).to.beLessThanOrEqualTo(noOfTotalUrls);
|
||||
expect(noOfTotalUrls).to.equal(imageURLs.count);
|
||||
} completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) {
|
||||
expect(numberOfPrefetched).to.equal(noOfFinishedUrls);
|
||||
expect(noOfFinishedUrls).to.equal(imageURLs.count);
|
||||
expect(noOfSkippedUrls).to.equal(0);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
- (void)test03PrefetchWithEmptyArrayWillCallTheCompletionWithAllZeros {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Prefetch with empty array"];
|
||||
|
||||
[[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:@[] progress:nil completed:^(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls) {
|
||||
expect(noOfFinishedUrls).to.equal(0);
|
||||
expect(noOfSkippedUrls).to.equal(0);
|
||||
[expectation fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
|
||||
}
|
||||
|
||||
// TODO: test the prefetcher delegate works
|
||||
|
||||
@end
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -10,9 +10,9 @@
|
|||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <Expecta.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
|
||||
#import "UIImage+MultiFormat.h"
|
||||
#import <SDWebImage/UIImage+MultiFormat.h>
|
||||
|
||||
|
||||
@interface UIImageMultiFormatTests : XCTestCase
|
||||
|
@ -22,18 +22,6 @@
|
|||
|
||||
@implementation UIImageMultiFormatTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testImageOrientationFromImageDataWithInvalidData {
|
||||
// sync download image
|
||||
SEL selector = @selector(sd_imageOrientationFromImageData:);
|
||||
|
|
Loading…
Reference in New Issue