Merge pull request #2278 from dreampiggy/refactor_cache_webcache_protocol

Refactor cache - Support custom web cache
This commit is contained in:
Bogdan Poplauschi 2018-04-18 14:06:50 +03:00 committed by GitHub
commit 5426a720f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1483 additions and 249 deletions

View File

@ -85,8 +85,7 @@
- (void)flushCache
{
[SDWebImageManager.sharedManager.imageCache clearMemory];
[SDWebImageManager.sharedManager.imageCache clearDiskOnCompletion:nil];
[SDWebImageManager.sharedManager.imageCache clearWithCacheType:SDImageCacheTypeAll completion:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

View File

@ -508,6 +508,30 @@
32CF1C101FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
32CF1C111FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
32CF1C121FA496B000004BD1 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */; };
32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221A2080B2EB003685A3 /* SDWebImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221B2080B2EB003685A3 /* SDWebImageCache.m */; };
32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */; };
32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
32EB6D8E206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
32EB6D8F206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
32EB6D90206D132E005CAEF6 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = 320224BA203979BA00E9F285 /* SDAnimatedImageRep.m */; };
@ -1572,6 +1596,10 @@
32C0FDE02013426C001B8F2D /* SDWebImageIndicator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageIndicator.m; sourceTree = "<group>"; };
32CF1C051FA496B000004BD1 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoderHelper.h; sourceTree = "<group>"; };
32CF1C061FA496B000004BD1 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoderHelper.m; sourceTree = "<group>"; };
32D1221A2080B2EB003685A3 /* SDWebImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCache.h; sourceTree = "<group>"; };
32D1221B2080B2EB003685A3 /* SDWebImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCache.m; sourceTree = "<group>"; };
32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCachesManager.m; sourceTree = "<group>"; };
32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCachesManager.h; sourceTree = "<group>"; };
32F21B4F20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDownloaderRequestModifier.h; sourceTree = "<group>"; };
32F21B5020788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDownloaderRequestModifier.m; sourceTree = "<group>"; };
32F7C06D2030114C00873181 /* SDWebImageTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransformer.h; sourceTree = "<group>"; };
@ -2090,6 +2118,10 @@
328BB6C02082581100760D6C /* SDMemoryCache.m */,
328BB6BD2082581100760D6C /* SDDiskCache.h */,
328BB6BE2082581100760D6C /* SDDiskCache.m */,
32D1221A2080B2EB003685A3 /* SDWebImageCache.h */,
32D1221B2080B2EB003685A3 /* SDWebImageCache.m */,
32D1221D2080B2EB003685A3 /* SDWebImageCachesManager.h */,
32D1221C2080B2EB003685A3 /* SDWebImageCachesManager.m */,
);
name = Cache;
sourceTree = "<group>";
@ -2310,6 +2342,7 @@
323F8B531F38EF770092B609 /* backward_references_enc.h in Headers */,
4317395A1CDFC8B70008FEB9 /* mux_types.h in Headers */,
431739561CDFC8B70008FEB9 /* demux.h in Headers */,
32D122212080B2EB003685A3 /* SDWebImageCache.h in Headers */,
32B9B53A206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
328BB6AD2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */,
80377C4A1F2F666300F89830 /* bit_writer_utils.h in Headers */,
@ -2379,6 +2412,7 @@
3248476C201775F600AF9E5A /* SDAnimatedImageView.h in Headers */,
80377C5F1F2F666300F89830 /* utils.h in Headers */,
80377C5B1F2F666300F89830 /* rescaler_utils.h in Headers */,
32D122332080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
323F8BF91F38EF770092B609 /* animi.h in Headers */,
32F7C0872030719600873181 /* UIImage+Transform.h in Headers */,
80377C4F1F2F666300F89830 /* filters_utils.h in Headers */,
@ -2406,6 +2440,7 @@
80377C1D1F2F666300F89830 /* huffman_encode_utils.h in Headers */,
321E60B11F38E90100405457 /* SDWebImageWebPCoder.h in Headers */,
80377E9A1F2F66D400F89830 /* common_dec.h in Headers */,
32D1221F2080B2EB003685A3 /* SDWebImageCache.h in Headers */,
327054D5206CD8B3006EA328 /* SDWebImageAPNGCoder.h in Headers */,
328BB6AB2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */,
32B9B538206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
@ -2447,6 +2482,7 @@
80377C271F2F666300F89830 /* rescaler_utils.h in Headers */,
323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */,
325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */,
32D122312080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
4314D1741D0E0E3B004B36C9 /* types.h in Headers */,
4314D1761D0E0E3B004B36C9 /* decode.h in Headers */,
@ -2528,6 +2564,7 @@
80377E211F2F66A800F89830 /* neon.h in Headers */,
80377C711F2F666400F89830 /* quant_levels_utils.h in Headers */,
323F8B541F38EF770092B609 /* backward_references_enc.h in Headers */,
32D122342080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
32F7C0882030719600873181 /* UIImage+Transform.h in Headers */,
43A62A1F1D0E0A800089D7DD /* mux.h in Headers */,
431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */,
@ -2572,6 +2609,7 @@
32F7C0732030114C00873181 /* SDWebImageTransformer.h in Headers */,
431BB6FA1D06D2C1006A3455 /* SDWebImageDownloader.h in Headers */,
3248476D201775F600AF9E5A /* SDAnimatedImageView.h in Headers */,
32D122222080B2EB003685A3 /* SDWebImageCache.h in Headers */,
80377DF51F2F66A800F89830 /* common_sse2.h in Headers */,
323F8BDC1F38EF770092B609 /* vp8i_enc.h in Headers */,
80377ED21F2F66D500F89830 /* vp8i_dec.h in Headers */,
@ -2592,6 +2630,7 @@
32F7C0892030719600873181 /* UIImage+Transform.h in Headers */,
80377EDA1F2F66D500F89830 /* common_dec.h in Headers */,
80377EE61F2F66D500F89830 /* webpi_dec.h in Headers */,
32D122232080B2EB003685A3 /* SDWebImageCache.h in Headers */,
32B9B53C206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
328BB6AF2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */,
4397D2BA1D0DDD8C00BB2784 /* demux.h in Headers */,
@ -2661,6 +2700,7 @@
321E608B1F38E8C800405457 /* SDWebImageCoder.h in Headers */,
323F8B731F38EF770092B609 /* delta_palettization_enc.h in Headers */,
321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
32D122352080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
32484768201775F600AF9E5A /* SDAnimatedImageView+WebCache.h in Headers */,
80377E561F2F66A800F89830 /* lossless_common.h in Headers */,
4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */,
@ -2689,6 +2729,7 @@
323F8B521F38EF770092B609 /* backward_references_enc.h in Headers */,
4317394F1CDFC8B70008FEB9 /* demux.h in Headers */,
43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */,
32D122202080B2EB003685A3 /* SDWebImageCache.h in Headers */,
32B9B539206ED4230026769D /* SDWebImageDownloaderConfig.h in Headers */,
328BB6AC2081FEE500760D6C /* SDWebImageCacheSerializer.h in Headers */,
80377C301F2F666300F89830 /* bit_writer_utils.h in Headers */,
@ -2758,6 +2799,7 @@
3248476B201775F600AF9E5A /* SDAnimatedImageView.h in Headers */,
4A2CAE311AB4BB7500B6BC39 /* UIImage+WebP.h in Headers */,
323F8BF81F38EF770092B609 /* animi.h in Headers */,
32D122322080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
80377C351F2F666300F89830 /* filters_utils.h in Headers */,
32F7C0862030719600873181 /* UIImage+Transform.h in Headers */,
80377C321F2F666300F89830 /* color_cache_utils.h in Headers */,
@ -2811,6 +2853,7 @@
431738BD1CDFC2660008FEB9 /* decode.h in Headers */,
80377D0B1F2F66A100F89830 /* mips_macro.h in Headers */,
329A18591FFF5DFD008C9A2F /* UIImage+WebCache.h in Headers */,
32D122302080B2EB003685A3 /* SDWebImageCachesManager.h in Headers */,
5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */,
328BB6CD2082581100760D6C /* SDMemoryCache.h in Headers */,
4369C2771D9807EC007E863A /* UIView+WebCache.h in Headers */,
@ -2858,6 +2901,7 @@
323F8B6E1F38EF770092B609 /* delta_palettization_enc.h in Headers */,
438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */,
43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */,
32D1221E2080B2EB003685A3 /* SDWebImageCache.h in Headers */,
80377E8A1F2F66D000F89830 /* common_dec.h in Headers */,
AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */,
323F8B501F38EF770092B609 /* backward_references_enc.h in Headers */,
@ -3174,6 +3218,7 @@
80377DDE1F2F66A700F89830 /* rescaler_mips32.c in Sources */,
80377DCA1F2F66A700F89830 /* filters_sse2.c in Sources */,
80377EBE1F2F66D500F89830 /* quant_dec.c in Sources */,
32D1222D2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
80377DB61F2F66A700F89830 /* dec_clip_tables.c in Sources */,
80377C5E1F2F666300F89830 /* utils.c in Sources */,
32B9B540206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
@ -3216,6 +3261,7 @@
80377DB51F2F66A700F89830 /* cpu.c in Sources */,
80377EC51F2F66D500F89830 /* webp_dec.c in Sources */,
80377DD61F2F66A700F89830 /* lossless_neon.c in Sources */,
32D122272080B2EB003685A3 /* SDWebImageCache.m in Sources */,
00733A5C1BC4880000A5A117 /* UIButton+WebCache.m in Sources */,
80377EC01F2F66D500F89830 /* vp8_dec.c in Sources */,
80377C521F2F666300F89830 /* huffman_utils.c in Sources */,
@ -3299,6 +3345,7 @@
4314D1341D0E0E3B004B36C9 /* UIImage+WebP.m in Sources */,
80377D3D1F2F66A700F89830 /* filters_mips_dsp_r2.c in Sources */,
323F8B751F38EF770092B609 /* filter_enc.c in Sources */,
32D122252080B2EB003685A3 /* SDWebImageCache.m in Sources */,
80377D401F2F66A700F89830 /* filters_sse2.c in Sources */,
80377D1E1F2F66A700F89830 /* alpha_processing_mips_dsp_r2.c in Sources */,
80377D291F2F66A700F89830 /* cost_sse2.c in Sources */,
@ -3342,6 +3389,7 @@
80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */,
323F8C151F38EF770092B609 /* muxinternal.c in Sources */,
80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */,
32D1222B2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
43C892A11D9D6DDC0022038D /* demux.c in Sources */,
80377C131F2F666300F89830 /* bit_reader_utils.c in Sources */,
80377E9C1F2F66D400F89830 /* idec_dec.c in Sources */,
@ -3461,6 +3509,7 @@
323F8BE21F38EF770092B609 /* vp8l_enc.c in Sources */,
431BB6A31D06D2C1006A3455 /* UIImageView+WebCache.m in Sources */,
80377E0C1F2F66A800F89830 /* filters_mips_dsp_r2.c in Sources */,
32D122282080B2EB003685A3 /* SDWebImageCache.m in Sources */,
323F8B781F38EF770092B609 /* filter_enc.c in Sources */,
4369C2821D9807EC007E863A /* UIView+WebCache.m in Sources */,
80377E0F1F2F66A800F89830 /* filters_sse2.c in Sources */,
@ -3504,6 +3553,7 @@
323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */,
80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */,
323F8C181F38EF770092B609 /* muxinternal.c in Sources */,
32D1222E2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
80377C741F2F666400F89830 /* rescaler_utils.c in Sources */,
431BB6B11D06D2C1006A3455 /* UIView+WebCacheOperation.m in Sources */,
80377DF01F2F66A800F89830 /* alpha_processing_sse41.c in Sources */,
@ -3642,6 +3692,7 @@
321E60C91F38E91700405457 /* UIImage+ForceDecode.m in Sources */,
80377E551F2F66A800F89830 /* filters.c in Sources */,
80377E731F2F66A800F89830 /* yuv_mips32.c in Sources */,
32D1222F2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
4397D2911D0DDD8C00BB2784 /* MKAnnotationView+WebCache.m in Sources */,
4397D2921D0DDD8C00BB2784 /* SDWebImagePrefetcher.m in Sources */,
323F8BBF1F38EF770092B609 /* predictor_enc.c in Sources */,
@ -3654,6 +3705,7 @@
80377E381F2F66A800F89830 /* argb_sse2.c in Sources */,
323F8B9B1F38EF770092B609 /* near_lossless_enc.c in Sources */,
32F21B5C20788D8C0036B1D5 /* SDWebImageDownloaderRequestModifier.m in Sources */,
32D122292080B2EB003685A3 /* SDWebImageCache.m in Sources */,
80377E3B1F2F66A800F89830 /* cost_mips_dsp_r2.c in Sources */,
4397D29B1D0DDD8C00BB2784 /* SDWebImageDownloader.m in Sources */,
80377E711F2F66A800F89830 /* upsampling.c in Sources */,
@ -3828,6 +3880,7 @@
80377C441F2F666300F89830 /* utils.c in Sources */,
80377D8D1F2F66A700F89830 /* lossless_enc_sse41.c in Sources */,
80377EAE1F2F66D400F89830 /* quant_dec.c in Sources */,
32D1222C2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
80377D6E1F2F66A700F89830 /* cost_sse2.c in Sources */,
80377D991F2F66A700F89830 /* rescaler_mips32.c in Sources */,
32B9B53F206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
@ -3870,6 +3923,7 @@
80377D8C1F2F66A700F89830 /* lossless_enc_sse2.c in Sources */,
4A2CAE2C1AB4BB7500B6BC39 /* UIButton+WebCache.m in Sources */,
80377EB51F2F66D400F89830 /* webp_dec.c in Sources */,
32D122262080B2EB003685A3 /* SDWebImageCache.m in Sources */,
80377D701F2F66A700F89830 /* cpu.c in Sources */,
80377D911F2F66A700F89830 /* lossless_neon.c in Sources */,
80377EB01F2F66D400F89830 /* vp8_dec.c in Sources */,
@ -3994,6 +4048,7 @@
80377D031F2F66A100F89830 /* lossless_enc_sse41.c in Sources */,
80377E8E1F2F66D000F89830 /* quant_dec.c in Sources */,
80377CE41F2F66A100F89830 /* cost_sse2.c in Sources */,
32D1222A2080B2EB003685A3 /* SDWebImageCachesManager.m in Sources */,
80377D0F1F2F66A100F89830 /* rescaler_mips32.c in Sources */,
323F8C081F38EF770092B609 /* muxedit.c in Sources */,
32B9B53D206ED4230026769D /* SDWebImageDownloaderConfig.m in Sources */,
@ -4036,6 +4091,7 @@
A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */,
80377E951F2F66D000F89830 /* webp_dec.c in Sources */,
80377CE61F2F66A100F89830 /* cpu.c in Sources */,
32D122242080B2EB003685A3 /* SDWebImageCache.m in Sources */,
80377D071F2F66A100F89830 /* lossless_neon.c in Sources */,
80377E901F2F66D000F89830 /* vp8_dec.c in Sources */,
80377C041F2F665300F89830 /* huffman_utils.c in Sources */,

View File

@ -10,21 +10,7 @@
#import "SDWebImageCompat.h"
#import "SDWebImageDefine.h"
#import "SDImageCacheConfig.h"
typedef NS_ENUM(NSInteger, SDImageCacheType) {
/**
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
*/
SDImageCacheTypeNone,
/**
* The image was obtained from the disk cache.
*/
SDImageCacheTypeDisk,
/**
* The image was obtained from the memory cache.
*/
SDImageCacheTypeMemory
};
#import "SDWebImageCache.h"
typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
/**
@ -60,11 +46,9 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
SDImageCachePreloadAllFrames = 1 << 6
};
typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
typedef void(^SDImageCacheCheckCompletionBlock)(BOOL isInCache);
typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache);
typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize);
typedef void(^SDImageCacheCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize);
typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString * _Nonnull key);
@ -181,6 +165,15 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
/**
* Synchronously store image into memory 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)storeImageToMemory:(nullable UIImage*)image
forKey:(nullable NSString *)key;
/**
* Synchronously store image NSData into disk cache at the given key.
*
@ -191,7 +184,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
forKey:(nullable NSString *)key;
#pragma mark - Query and Retrieve Ops
#pragma mark - Contains and Check Ops
/**
* Asynchronously check if image exists in disk cache already (does not load the image)
@ -200,7 +193,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
* @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;
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDImageCacheCheckCompletionBlock)completionBlock;
/**
* Synchronously check if image data exists in disk cache already (does not load the image)
@ -209,6 +202,8 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
*/
- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key;
#pragma mark - Query and Retrieve Ops
/**
* Asynchronously queries the cache with operation and call the completion when done.
*
@ -217,7 +212,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
*
* @return a NSOperation instance containing the cache op
*/
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock;
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDImageCacheQueryCompletionBlock)doneBlock;
/**
* Asynchronously queries the cache with operation and call the completion when done.
@ -228,7 +223,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
*
* @return a NSOperation instance containing the cache op
*/
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock;
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDImageCacheQueryCompletionBlock)doneBlock;
/**
* Asynchronously queries the cache with operation and call the completion when done.
@ -240,7 +235,7 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
*
* @return a NSOperation instance containing the cache op
*/
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock;
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock;
/**
* Synchronously query the memory cache.
@ -282,6 +277,20 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
*/
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion;
/**
Synchronously remove the image from memory cache.
@param key The unique image cache key
*/
- (void)removeImageFromMemoryForKey:(nullable NSString *)key;
/**
Synchronously remove the image from disk cache.
@param key The unique image cache key
*/
- (void)removeImageFromDiskForKey:(nullable NSString *)key;
#pragma mark - Cache clean Ops
/**
@ -316,6 +325,13 @@ typedef NSString * _Nullable (^SDImageCacheAdditionalCachePathBlock)(NSString *
/**
* Asynchronously calculate the disk cache's size.
*/
- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock;
- (void)calculateSizeWithCompletionBlock:(nullable SDImageCacheCalculateSizeBlock)completionBlock;
@end
/**
* SDImageCache is the built-in image cache implementation for web image manager. It adopts `SDWebImageCache` protocol to provide the function for web image manager to use for image loading process.
*/
@interface SDImageCache (SDWebImageCache) <SDWebImageCache>
@end

View File

@ -145,6 +145,15 @@
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
return [self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:toDisk completion:completionBlock];
}
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toMemory:(BOOL)toMemory
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
if (!image || !key) {
if (completionBlock) {
completionBlock();
@ -152,7 +161,7 @@
return;
}
// if memory cache is enabled
if (self.config.shouldCacheImagesInMemory) {
if (toMemory && self.config.shouldCacheImagesInMemory) {
NSUInteger cost = SDMemoryCacheCostForImage(image);
[self.memCache setObject:image forKey:key cost:cost];
}
@ -187,6 +196,14 @@
}
}
- (void)storeImageToMemory:(UIImage *)image forKey:(NSString *)key {
if (!image || !key) {
return;
}
NSUInteger cost = SDMemoryCacheCostForImage(image);
[self.memCache setObject:image forKey:key cost:cost];
}
- (void)storeImageDataToDisk:(nullable NSData *)imageData
forKey:(nullable NSString *)key {
if (!imageData || !key) {
@ -209,7 +226,7 @@
#pragma mark - Query and Retrieve Ops
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDImageCacheCheckCompletionBlock)completionBlock {
dispatch_async(self.ioQueue, ^{
BOOL exists = [self _diskImageDataExistsWithKey:key];
if (completionBlock) {
@ -300,56 +317,22 @@
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options context:(SDWebImageContext *)context {
if (data) {
UIImage *image;
BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly;
NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor];
CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(key);
if (!decodeFirstFrame) {
// check whether we should use `SDAnimatedImage`
if ([context valueForKey:SDWebImageContextAnimatedImageClass]) {
Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass];
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
image = [[animatedImageClass alloc] initWithData:data scale:scale];
if (options & SDImageCachePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
[((id<SDAnimatedImage>)image) preloadAllFrames];
}
}
}
}
if (!image) {
image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}];
}
BOOL shouldDecode = (options & SDImageCacheAvoidDecodeImage) == 0;
if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) {
// `SDAnimatedImage` do not decode
shouldDecode = NO;
} else if (image.sd_isAnimated) {
// animated image do not decode
shouldDecode = NO;
}
if (shouldDecode) {
BOOL shouldScaleDown = options & SDImageCacheScaleDownLargeImages;
if (shouldScaleDown) {
image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0];
} else {
image = [SDWebImageCoderHelper decodedImageWithImage:image];
}
}
UIImage *image = SDWebImageCacheDecodeImageData(data, key, [[self class] imageOptionsFromCacheOptions:options], context);
return image;
} else {
return nil;
}
}
- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock {
- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDImageCacheQueryCompletionBlock)doneBlock {
return [self queryCacheOperationForKey:key options:0 done:doneBlock];
}
- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDCacheQueryCompletedBlock)doneBlock {
- (nullable NSOperation *)queryCacheOperationForKey:(NSString *)key options:(SDImageCacheOptions)options done:(SDImageCacheQueryCompletionBlock)doneBlock {
return [self queryCacheOperationForKey:key options:options context:nil done:doneBlock];
}
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDCacheQueryCompletedBlock)doneBlock {
- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options context:(nullable SDWebImageContext *)context done:(nullable SDImageCacheQueryCompletionBlock)doneBlock {
if (!key) {
if (doneBlock) {
doneBlock(nil, nil, SDImageCacheTypeNone);
@ -426,11 +409,15 @@
}
- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion {
[self removeImageForKey:key fromMemory:YES fromDisk:fromDisk withCompletion:completion];
}
- (void)removeImageForKey:(nullable NSString *)key fromMemory:(BOOL)fromMemory fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion {
if (key == nil) {
return;
}
if (self.config.shouldCacheImagesInMemory) {
if (fromMemory && self.config.shouldCacheImagesInMemory) {
[self.memCache removeObjectForKey:key];
}
@ -449,6 +436,32 @@
}
}
- (void)removeImageFromMemoryForKey:(NSString *)key {
if (!key) {
return;
}
[self.memCache removeObjectForKey:key];
}
- (void)removeImageFromDiskForKey:(NSString *)key {
if (!key) {
return;
}
dispatch_sync(self.ioQueue, ^{
[self _removeImageFromDiskForKey:key];
});
}
// Make sure to call form io queue by caller
- (void)_removeImageFromDiskForKey:(NSString *)key {
if (!key) {
return;
}
[self.diskCache removeDataForKey:key];
}
#pragma mark - Cache clean Ops
- (void)clearMemory {
@ -530,7 +543,7 @@
return count;
}
- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock {
- (void)calculateSizeWithCompletionBlock:(nullable SDImageCacheCalculateSizeBlock)completionBlock {
dispatch_async(self.ioQueue, ^{
NSUInteger fileCount = [self.diskCache totalCount];
NSUInteger totalSize = [self.diskCache totalSize];
@ -542,5 +555,163 @@
});
}
#pragma mark - Helper
+ (SDWebImageOptions)imageOptionsFromCacheOptions:(SDImageCacheOptions)cacheOptions {
SDWebImageOptions options = 0;
if (cacheOptions & SDImageCacheScaleDownLargeImages) options |= SDWebImageScaleDownLargeImages;
if (cacheOptions & SDImageCacheDecodeFirstFrameOnly) options |= SDWebImageDecodeFirstFrameOnly;
if (cacheOptions & SDImageCachePreloadAllFrames) options |= SDWebImagePreloadAllFrames;
if (cacheOptions & SDImageCacheAvoidDecodeImage) options |= SDWebImageAvoidDecodeImage;
return options;
}
@end
@implementation SDImageCache (SDWebImageCache)
#pragma mark - SDWebImageCache
- (id<SDWebImageOperation>)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(nullable SDWebImageContext *)context completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock {
SDImageCacheOptions cacheOptions = 0;
if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory;
if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync;
if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage;
if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly;
if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames;
return [self queryCacheOperationForKey:key options:cacheOptions context:context done:completionBlock];
}
- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(nullable NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock {
switch (cacheType) {
case SDImageCacheTypeNone: {
[self storeImage:image imageData:imageData forKey:key toMemory:NO toDisk:NO completion:completionBlock];
}
break;
case SDImageCacheTypeMemory: {
[self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:NO completion:completionBlock];
}
break;
case SDImageCacheTypeDisk: {
[self storeImage:image imageData:imageData forKey:key toMemory:NO toDisk:YES completion:completionBlock];
}
break;
case SDImageCacheTypeAll: {
[self storeImage:image imageData:imageData forKey:key toMemory:YES toDisk:YES completion:completionBlock];
}
break;
default: {
if (completionBlock) {
completionBlock();
}
}
break;
}
}
- (void)removeImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDWebImageNoParamsBlock)completionBlock {
switch (cacheType) {
case SDImageCacheTypeNone: {
[self removeImageForKey:key fromMemory:NO fromDisk:NO withCompletion:completionBlock];
}
break;
case SDImageCacheTypeMemory: {
[self removeImageForKey:key fromMemory:YES fromDisk:NO withCompletion:completionBlock];
}
break;
case SDImageCacheTypeDisk: {
[self removeImageForKey:key fromMemory:NO fromDisk:YES withCompletion:completionBlock];
}
break;
case SDImageCacheTypeAll: {
[self removeImageForKey:key fromMemory:YES fromDisk:YES withCompletion:completionBlock];
}
break;
default: {
if (completionBlock) {
completionBlock();
}
}
break;
}
}
- (void)containsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock {
switch (cacheType) {
case SDImageCacheTypeNone: {
if (completionBlock) {
completionBlock(SDImageCacheTypeNone);
}
}
break;
case SDImageCacheTypeMemory: {
BOOL isInMemoryCache = ([self imageFromMemoryCacheForKey:key] != nil);
if (completionBlock) {
completionBlock(isInMemoryCache ? SDImageCacheTypeMemory : SDImageCacheTypeNone);
}
}
break;
case SDImageCacheTypeDisk: {
[self diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
if (completionBlock) {
completionBlock(isInDiskCache ? SDImageCacheTypeDisk : SDImageCacheTypeNone);
}
}];
}
break;
case SDImageCacheTypeAll: {
BOOL isInMemoryCache = ([self imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
if (completionBlock) {
completionBlock(SDImageCacheTypeMemory);
}
return;
}
[self diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
if (completionBlock) {
completionBlock(isInDiskCache ? SDImageCacheTypeDisk : SDImageCacheTypeNone);
}
}];
}
break;
default:
if (completionBlock) {
completionBlock(SDImageCacheTypeNone);
}
break;
}
}
- (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock {
switch (cacheType) {
case SDImageCacheTypeNone: {
return;
}
break;
case SDImageCacheTypeMemory: {
[self clearMemory];
if (completionBlock) {
completionBlock();
}
}
break;
case SDImageCacheTypeDisk: {
[self clearDiskOnCompletion:completionBlock];
}
break;
case SDImageCacheTypeAll: {
[self clearMemory];
[self clearDiskOnCompletion:completionBlock];
}
break;
default: {
if (completionBlock) {
completionBlock();
}
}
break;
}
}
@end

View File

@ -0,0 +1,121 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
#import "SDWebImageOperation.h"
#import "SDWebImageDefine.h"
typedef NS_ENUM(NSInteger, SDImageCacheType) {
/**
* For query and contains op in response, means the image isn't available in the image cache
* For op in request, this type is not available and take no effect.
*/
SDImageCacheTypeNone,
/**
* For query and contains op in response, means the image was obtained from the disk cache.
* For op in request, means process only disk cache.
*/
SDImageCacheTypeDisk,
/**
* For query and contains op in response, means the image was obtained from the memory cache.
* For op in request, means process only memory cache.
*/
SDImageCacheTypeMemory,
/**
* For query and contains op in response, this type is not available and take no effect.
* For op in request, means process both memory cache and disk cache.
*/
SDImageCacheTypeAll
};
typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType);
/**
This is the built-in decoding process for image query from cache.
@note If you want to implement your custom loader with `queryImageForKey:options:context:completion:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image.
@param imageData The image data from the cache. Should not be nil
@param cacheKey The image cache key from the input. Should not be nil
@param options The options arg from the input
@param context The context arg from the input
@return The decoded image for current image data query from cache
*/
FOUNDATION_EXPORT UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context);
/**
This is the image cache protocol to provide custom image cache for `SDWebImageManager`.
Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`).
However, if your own cache implementation contains more advanced feature beyond `SDImageCache` itself, you can consider to provide this instead. For example, you can even use a cache manager like `SDWebImageCachesManager` to register multiple caches.
*/
@protocol SDWebImageCache <NSObject>
@required
/**
Query the cached image from image cache for given key. The operation can be used to cancel the query.
If image is cached in memory, completion is called synchronously, else aynchronously and depends on the options arg (See `SDWebImageQueryDiskSync`)
@param key The image cache key
@param options A mask to specify options to use for this query
@param context A context contains different options to perform specify changes or processes, see `SDWebImageContextOption`. This hold the extra objects which `options` enum can not hold.
@param completionBlock The completion block. Will not get called if the operation is cancelled
@return The operation for this query
*/
- (nullable id<SDWebImageOperation>)queryImageForKey:(nullable NSString *)key
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
completion:(nullable SDImageCacheQueryCompletionBlock)completionBlock;
/**
Store the image into image cache for the given key. If cache type is memory only, completion is called synchronously, else aynchronously.
@param image The image to store
@param imageData The image data to be used for disk storage
@param key The image cache key
@param cacheType The image store op cache type
@param completionBlock A block executed after the operation is finished
*/
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
/**
Remove the image from image cache for the given key. If cache type is memory only, completion is called synchronously, else aynchronously.
@param key The image cache key
@param cacheType The image remove op cache type
@param completionBlock A block executed after the operation is finished
*/
- (void)removeImageForKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
/**
Check if image cache contains the image for the given key (does not load the image). If image is cached in memory, completion is called synchronously, else aynchronously.
@param key The image cache key
@param cacheType The image contains op cache type
@param completionBlock A block executed after the operation is finished.
*/
- (void)containsImageForKey:(nullable NSString *)key
cacheType:(SDImageCacheType)cacheType
completion:(nullable SDImageCacheContainsCompletionBlock)completionBlock;
/**
Clear all the cached images for image cache. If cache type is memory only, completion is called synchronously, else aynchronously.
@param cacheType The image clear op cache type
@param completionBlock A block executed after the operation is finished
*/
- (void)clearWithCacheType:(SDImageCacheType)cacheType
completion:(nullable SDWebImageNoParamsBlock)completionBlock;
@end

View File

@ -0,0 +1,58 @@
/*
* 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 "SDWebImageCache.h"
#import "SDWebImageCodersManager.h"
#import "SDWebImageCoderHelper.h"
#import "SDAnimatedImage.h"
#import "UIImage+WebCache.h"
UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
UIImage *image;
BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly;
NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor];
CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey);
if (scale < 1) {
scale = 1;
}
if (!decodeFirstFrame) {
// check whether we should use `SDAnimatedImage`
if ([context valueForKey:SDWebImageContextAnimatedImageClass]) {
Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass];
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
image = [[animatedImageClass alloc] initWithData:imageData scale:scale];
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
[((id<SDAnimatedImage>)image) preloadAllFrames];
}
}
}
}
if (!image) {
image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}];
}
if (image) {
BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0;
if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) {
// `SDAnimatedImage` do not decode
shouldDecode = NO;
} else if (image.sd_isAnimated) {
// animated image do not decode
shouldDecode = NO;
}
if (shouldDecode) {
BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages;
if (shouldScaleDown) {
image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0];
} else {
image = [SDWebImageCoderHelper decodedImageWithImage:image];
}
}
}
return image;
}

View File

@ -0,0 +1,77 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCache.h"
typedef NS_ENUM(NSUInteger, SDWebImageCachesManagerOperationPolicy) {
SDWebImageCachesManagerOperationPolicySerial, // process all caches serially (from the highest priority to the lowest priority cache by order)
SDWebImageCachesManagerOperationPolicyConcurrent, // process all caches concurrently
SDWebImageCachesManagerOperationPolicyHighestOnly, // process the highest priority cache only
SDWebImageCachesManagerOperationPolicyLowestOnly // process the lowest priority cache only
};
@interface SDWebImageCachesManager : NSObject <SDWebImageCache>
/**
Returns the global shared caches manager instance.
*/
@property (nonatomic, class, readonly, nonnull) SDWebImageCachesManager *sharedManager;
// These are op policy for cache manager.
/**
Operation policy for query op.
Defaults to `Serial`, means query all caches serially (one completion called then next begin) until one cache query success (`image` != nil).
*/
@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy queryOperationPolicy;
/**
Operation policy for store op.
Defaults to `HighestOnly`, means store to the highest priority cache only.
*/
@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy storeOperationPolicy;
/**
Operation policy for remove op.
Defaults to `Concurrent`, means remove all caches concurrently.
*/
@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy removeOperationPolicy;
/**
Operation policy for contains op.
Defaults to `Serial`, means check all caches serially (one completion called then next begin) until one cache check success (`containsCacheType` != None).
*/
@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy containsOperationPolicy;
/**
Operation policy for clear op.
Defaults to `Concurrent`, means clear all caches concurrently.
*/
@property (nonatomic, assign) SDWebImageCachesManagerOperationPolicy clearOperationPolicy;
/**
All caches in caches manager. The caches array is a priority queue, which means the later added cache will have the highest priority
*/
@property (atomic, copy, readwrite, nullable) NSArray<id<SDWebImageCache>> *caches;
/**
Add a new cache to the end of caches array. Which has the highest priority.
@param cache cache
*/
- (void)addCache:(nonnull id<SDWebImageCache>)cache;
/**
Remove a cache in the caches array.
@param cache cache
*/
- (void)removeCache:(nonnull id<SDWebImageCache>)cache;
@end

View File

@ -0,0 +1,582 @@
/*
* 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 "SDWebImageCachesManager.h"
// This is used for operation management, but not for operation queue execute
@interface SDWebImageCachesManagerOperation : NSOperation
@property (nonatomic, assign, readonly) NSUInteger pendingCount;
- (void)beginWithTotalCount:(NSUInteger)totalCount;
- (void)completeOne;
- (void)done;
@end
@implementation SDWebImageCachesManagerOperation
@synthesize executing = _executing;
@synthesize finished = _finished;
@synthesize cancelled = _cancelled;
- (void)beginWithTotalCount:(NSUInteger)totalCount {
self.executing = YES;
self.finished = NO;
_pendingCount = totalCount;
}
- (void)completeOne {
_pendingCount = _pendingCount > 0 ? _pendingCount - 1 : 0;
}
- (void)cancel {
self.cancelled = YES;
[self reset];
}
- (void)done {
self.finished = YES;
self.executing = NO;
[self reset];
}
- (void)reset {
_pendingCount = 0;
}
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
- (void)setExecuting:(BOOL)executing {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
- (void)setCancelled:(BOOL)cancelled {
[self willChangeValueForKey:@"isCancelled"];
_cancelled = cancelled;
[self didChangeValueForKey:@"isCancelled"];
}
@end
@implementation SDWebImageCachesManager
+ (SDWebImageCachesManager *)sharedManager {
static dispatch_once_t onceToken;
static SDWebImageCachesManager *manager;
dispatch_once(&onceToken, ^{
manager = [[SDWebImageCachesManager alloc] init];
});
return manager;
}
- (instancetype)init {
self = [super init];
if (self) {
self.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
self.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
self.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
self.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
self.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
}
return self;
}
#pragma mark - Cache IO operations
- (void)addCache:(id<SDWebImageCache>)cache {
if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) {
return;
}
NSMutableArray<id<SDWebImageCache>> *mutableCaches = [self.caches mutableCopy];
if (!mutableCaches) {
mutableCaches = [NSMutableArray array];
}
[mutableCaches addObject:cache];
self.caches = [mutableCaches copy];
}
- (void)removeCache:(id<SDWebImageCache>)cache {
if (![cache conformsToProtocol:@protocol(SDWebImageCache)]) {
return;
}
NSMutableArray<id<SDWebImageCache>> *mutableCaches = [self.caches mutableCopy];
[mutableCaches removeObject:cache];
self.caches = [mutableCaches copy];
}
#pragma mark - SDWebImageCache
- (id<SDWebImageOperation>)queryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock {
if (!key) {
return nil;
}
NSArray<id<SDWebImageCache>> *caches = [self.caches copy];
NSUInteger count = caches.count;
if (count == 0) {
return nil;
} else if (count == 1) {
return [caches.firstObject queryImageForKey:key options:options context:context completion:completionBlock];
}
switch (self.queryOperationPolicy) {
case SDWebImageCachesManagerOperationPolicyHighestOnly: {
id<SDWebImageCache> cache = caches.lastObject;
return [cache queryImageForKey:key options:options context:context completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyLowestOnly: {
id<SDWebImageCache> cache = caches.firstObject;
return [cache queryImageForKey:key options:options context:context completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyConcurrent: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self concurrentQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
return operation;
}
break;
case SDWebImageCachesManagerOperationPolicySerial: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
return operation;
}
break;
default:
return nil;
break;
}
}
- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock {
if (!key) {
return;
}
NSArray<id<SDWebImageCache>> *caches = [self.caches copy];
NSUInteger count = caches.count;
if (count == 0) {
return;
} else if (count == 1) {
[caches.firstObject storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock];
return;
}
switch (self.storeOperationPolicy) {
case SDWebImageCachesManagerOperationPolicyHighestOnly: {
id<SDWebImageCache> cache = caches.lastObject;
[cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyLowestOnly: {
id<SDWebImageCache> cache = caches.firstObject;
[cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyConcurrent: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self concurrentStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
}
break;
case SDWebImageCachesManagerOperationPolicySerial: {
[self serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator];
}
break;
default:
break;
}
}
- (void)removeImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock {
if (!key) {
return;
}
NSArray<id<SDWebImageCache>> *caches = [self.caches copy];
NSUInteger count = caches.count;
if (count == 0) {
return;
} else if (count == 1) {
[caches.firstObject removeImageForKey:key cacheType:cacheType completion:completionBlock];
return;
}
switch (self.removeOperationPolicy) {
case SDWebImageCachesManagerOperationPolicyHighestOnly: {
id<SDWebImageCache> cache = caches.lastObject;
[cache removeImageForKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyLowestOnly: {
id<SDWebImageCache> cache = caches.firstObject;
[cache removeImageForKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyConcurrent: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self concurrentRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
}
break;
case SDWebImageCachesManagerOperationPolicySerial: {
[self serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator];
}
break;
default:
break;
}
}
- (void)containsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock {
if (!key) {
return;
}
NSArray<id<SDWebImageCache>> *caches = [self.caches copy];
NSUInteger count = caches.count;
if (count == 0) {
return;
} else if (count == 1) {
[caches.firstObject containsImageForKey:key cacheType:cacheType completion:completionBlock];
return;
}
switch (self.clearOperationPolicy) {
case SDWebImageCachesManagerOperationPolicyHighestOnly: {
id<SDWebImageCache> cache = caches.lastObject;
[cache containsImageForKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyLowestOnly: {
id<SDWebImageCache> cache = caches.firstObject;
[cache containsImageForKey:key cacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyConcurrent: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self concurrentContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
}
break;
case SDWebImageCachesManagerOperationPolicySerial: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
}
break;
default:
break;
}
}
- (void)clearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock {
NSArray<id<SDWebImageCache>> *caches = [self.caches copy];
NSUInteger count = caches.count;
if (count == 0) {
return;
} else if (count == 1) {
[caches.firstObject clearWithCacheType:cacheType completion:completionBlock];
return;
}
switch (self.clearOperationPolicy) {
case SDWebImageCachesManagerOperationPolicyHighestOnly: {
id<SDWebImageCache> cache = caches.lastObject;
[cache clearWithCacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyLowestOnly: {
id<SDWebImageCache> cache = caches.firstObject;
[cache clearWithCacheType:cacheType completion:completionBlock];
}
break;
case SDWebImageCachesManagerOperationPolicyConcurrent: {
SDWebImageCachesManagerOperation *operation = [SDWebImageCachesManagerOperation new];
[operation beginWithTotalCount:caches.count];
[self concurrentClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator operation:operation];
}
break;
case SDWebImageCachesManagerOperationPolicySerial: {
[self serialClearWithCacheType:cacheType completion:completionBlock enumerator:caches.reverseObjectEnumerator];
}
break;
default:
break;
}
}
#pragma mark - Concurrent Operation
- (void)concurrentQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
for (id<SDWebImageCache> cache in enumerator) {
[cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (image) {
// Success
[operation done];
if (completionBlock) {
completionBlock(image, data, cacheType);
}
return;
}
if (operation.pendingCount == 0) {
// Complete
[operation done];
if (completionBlock) {
completionBlock(nil, nil, SDImageCacheTypeNone);
}
}
}];
}
}
- (void)concurrentStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
for (id<SDWebImageCache> cache in enumerator) {
[cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (operation.pendingCount == 0) {
// Complete
[operation done];
if (completionBlock) {
completionBlock();
}
}
}];
}
}
- (void)concurrentRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
for (id<SDWebImageCache> cache in enumerator) {
[cache removeImageForKey:key cacheType:cacheType completion:^{
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (operation.pendingCount == 0) {
// Complete
[operation done];
if (completionBlock) {
completionBlock();
}
}
}];
}
}
- (void)concurrentContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
for (id<SDWebImageCache> cache in enumerator) {
[cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) {
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (containsCacheType != SDImageCacheTypeNone) {
// Success
[operation done];
if (completionBlock) {
completionBlock(containsCacheType);
}
return;
}
if (operation.pendingCount == 0) {
// Complete
[operation done];
if (completionBlock) {
completionBlock(SDImageCacheTypeNone);
}
}
}];
}
}
- (void)concurrentClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
for (id<SDWebImageCache> cache in enumerator) {
[cache clearWithCacheType:cacheType completion:^{
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (operation.pendingCount == 0) {
// Complete
[operation done];
if (completionBlock) {
completionBlock();
}
}
}];
}
}
#pragma mark - Serial Operation
- (void)serialQueryImageForKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context completion:(SDImageCacheQueryCompletionBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
id<SDWebImageCache> cache = enumerator.nextObject;
if (!cache) {
// Complete
[operation done];
if (completionBlock) {
completionBlock(nil, nil, SDImageCacheTypeNone);
}
return;
}
__weak typeof(self) wself = self;
[cache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (image) {
// Success
[operation done];
if (completionBlock) {
completionBlock(image, data, cacheType);
}
return;
}
// Next
[wself serialQueryImageForKey:key options:options context:context completion:completionBlock enumerator:enumerator operation:operation];
}];
}
- (void)serialStoreImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator {
NSParameterAssert(enumerator);
id<SDWebImageCache> cache = enumerator.nextObject;
if (!cache) {
// Complete
if (completionBlock) {
completionBlock();
}
return;
}
__weak typeof(self) wself = self;
[cache storeImage:image imageData:imageData forKey:key cacheType:cacheType completion:^{
// Next
[wself serialStoreImage:image imageData:imageData forKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator];
}];
}
- (void)serialRemoveImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator {
NSParameterAssert(enumerator);
id<SDWebImageCache> cache = enumerator.nextObject;
if (!cache) {
// Complete
if (completionBlock) {
completionBlock();
}
return;
}
__weak typeof(self) wself = self;
[cache removeImageForKey:key cacheType:cacheType completion:^{
// Next
[wself serialRemoveImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator];
}];
}
- (void)serialContainsImageForKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDImageCacheContainsCompletionBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator operation:(SDWebImageCachesManagerOperation *)operation {
NSParameterAssert(enumerator);
NSParameterAssert(operation);
id<SDWebImageCache> cache = enumerator.nextObject;
if (!cache) {
// Complete
[operation done];
if (completionBlock) {
completionBlock(SDImageCacheTypeNone);
}
return;
}
__weak typeof(self) wself = self;
[cache containsImageForKey:key cacheType:cacheType completion:^(SDImageCacheType containsCacheType) {
if (operation.isCancelled) {
// Cancelled
return;
}
if (operation.isFinished) {
// Finished
return;
}
[operation completeOne];
if (containsCacheType != SDImageCacheTypeNone) {
// Success
[operation done];
if (completionBlock) {
completionBlock(containsCacheType);
}
return;
}
// Next
[wself serialContainsImageForKey:key cacheType:cacheType completion:completionBlock enumerator:enumerator operation:operation];
}];
}
- (void)serialClearWithCacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock enumerator:(NSEnumerator<id<SDWebImageCache>> *)enumerator {
NSParameterAssert(enumerator);
id<SDWebImageCache> cache = enumerator.nextObject;
if (!cache) {
// Complete
if (completionBlock) {
completionBlock();
}
return;
}
__weak typeof(self) wself = self;
[cache clearWithCacheType:cacheType completion:^{
// Next
[wself serialClearWithCacheType:cacheType completion:completionBlock enumerator:enumerator];
}];
}
@end

View File

@ -8,8 +8,8 @@
#import "SDWebImageCompat.h"
#import "SDWebImageOperation.h"
#import "SDWebImageCache.h"
#import "SDWebImageDownloader.h"
#import "SDImageCache.h"
#import "SDWebImageTransformer.h"
#import "SDWebImageCacheKeyFilter.h"
#import "SDWebImageCacheSerializer.h"
@ -99,7 +99,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
/**
* The image cache used by manager to query image cache.
*/
@property (strong, nonatomic, readonly, nonnull) SDImageCache *imageCache;
@property (strong, nonatomic, readonly, nonnull) id<SDWebImageCache> imageCache;
/**
* The image downloader used by manager to download image.
@ -154,6 +154,18 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
*/
@property (nonatomic, assign, readonly, getter=isRunning) BOOL running;
/**
The default image cache when the manager which is created with no arguments. Such as shared manager or init.
Defaults to nil. Means using `SDImageCache.sharedImageCache`
*/
@property (nonatomic, class, nullable) id<SDWebImageCache> defaultImageCache;
/**
The default image downloader for manager which is created with no arguments. Such as shared manager or init.
Defaults to nil. Means using `SDWebImageDownloader.sharedDownloader`
*/
@property (nonatomic, class, nullable) SDWebImageDownloader *defaultImageDownloader;
/**
* Returns global shared manager instance.
*/
@ -163,7 +175,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
* Allows to specify instance of cache and image downloader used with image manager.
* @return new instance of `SDWebImageManager` with specified cache and downloader.
*/
- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithCache:(nonnull id<SDWebImageCache>)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER;
/**
* Downloads the image at the given URL if not present in cache or return the cached version otherwise.
@ -213,46 +225,13 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
/**
* Saves image to cache for given URL
*
* @param image The image to cache
* @param url The URL to the image
*
*/
- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url;
/**
* Cancel all current operations
*/
- (void)cancelAll;
/**
* Async check if image has already been cached
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
- (void)cachedImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
* Async check if image has already been cached on disk only
*
* @param url image url
* @param completionBlock the block to be executed when the check is finished
*
* @note the completion block is always executed on the main queue
*/
- (void)diskImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
/**
*Return the cache key for a given URL
* Return the cache key for a given URL
*/
- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url;

View File

@ -7,11 +7,15 @@
*/
#import "SDWebImageManager.h"
#import "SDImageCache.h"
#import "NSImage+Additions.h"
#import "UIImage+WebCache.h"
#import "SDAnimatedImage.h"
#import "SDWebImageError.h"
static id<SDWebImageCache> _defaultImageCache;
static SDWebImageDownloader *_defaultImageDownloader;
@interface SDWebImageCombinedOperation ()
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@ -32,6 +36,28 @@
@implementation SDWebImageManager
+ (id<SDWebImageCache>)defaultImageCache {
return _defaultImageCache;
}
+ (void)setDefaultImageCache:(id<SDWebImageCache>)defaultImageCache {
if (defaultImageCache && ![defaultImageCache conformsToProtocol:@protocol(SDWebImageCache)]) {
return;
}
_defaultImageCache = defaultImageCache;
}
+ (SDWebImageDownloader *)defaultImageDownloader {
return _defaultImageDownloader;
}
+ (void)setDefaultImageDownloader:(SDWebImageDownloader *)defaultImageDownloader {
if (defaultImageDownloader && ![defaultImageDownloader isKindOfClass:[SDWebImageDownloader class]]) {
return;
}
_defaultImageDownloader = defaultImageDownloader;
}
+ (nonnull instancetype)sharedManager {
static dispatch_once_t once;
static id instance;
@ -42,12 +68,18 @@
}
- (nonnull instancetype)init {
SDImageCache *cache = [SDImageCache sharedImageCache];
SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader];
id<SDWebImageCache> cache = [[self class] defaultImageCache];
if (!cache) {
cache = [SDImageCache sharedImageCache];
}
SDWebImageDownloader *downloader = [[self class] defaultImageDownloader];
if (!downloader) {
downloader = [SDWebImageDownloader sharedDownloader];
}
return [self initWithCache:cache downloader:downloader];
}
- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader {
- (nonnull instancetype)initWithCache:(nonnull id<SDWebImageCache>)cache downloader:(nonnull SDWebImageDownloader *)downloader {
if ((self = [super init])) {
_imageCache = cache;
_imageDownloader = downloader;
@ -77,42 +109,6 @@
return SDScaledImageForKey(key, image);
}
- (void)cachedImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);
if (isInMemoryCache) {
// making sure we call the completion block on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(YES);
}
});
return;
}
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
- (void)diskImageExistsForURL:(nullable NSURL *)url
completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
NSString *key = [self cacheKeyForURL:url];
[self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) {
// the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch
if (completionBlock) {
completionBlock(isInDiskCache);
}
}];
}
- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock {
return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock];
}
@ -155,14 +151,6 @@
[self.runningOperations addObject:operation];
}
SDImageCacheOptions cacheOptions = 0;
if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory;
if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync;
if (options & SDWebImageScaleDownLargeImages) cacheOptions |= SDImageCacheScaleDownLargeImages;
if (options & SDWebImageTransformAnimatedImage) cacheOptions |= SDImageCacheTransformAnimatedImage;
if (options & SDWebImageDecodeFirstFrameOnly) cacheOptions |= SDImageCacheDecodeFirstFrameOnly;
if (options & SDWebImagePreloadAllFrames) cacheOptions |= SDImageCachePreloadAllFrames;
// Image transformer
id<SDWebImageTransformer> transformer;
if ([context valueForKey:SDWebImageContextCustomTransformer]) {
@ -196,7 +184,7 @@
}
__weak SDWebImageCombinedOperation *weakOperation = operation;
operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions context:context done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) {
operation.cacheOperation = [self.imageCache queryImageForKey:key options:options context:context completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) {
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (!strongOperation || strongOperation.isCancelled) {
[self safelyRemoveOperationFromRunning:strongOperation];
@ -272,7 +260,10 @@
}
}
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
SDImageCacheType storeCacheType = SDImageCacheTypeAll;
if (options & SDWebImageCacheMemoryOnly) {
storeCacheType = SDImageCacheTypeMemory;
}
// We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale.
if (self != [SDWebImageManager sharedManager] && cacheKeyFilter && downloadedImage && ![downloadedImage conformsToProtocol:@protocol(SDAnimatedImage)]) {
@ -295,7 +286,7 @@
} else {
cacheData = (imageWasTransformed ? nil : downloadedData);
}
[self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey toDisk:cacheOnDisk completion:nil];
[self.imageCache storeImage:transformedImage imageData:cacheData forKey:cacheKey cacheType:storeCacheType completion:nil];
}
[self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
@ -305,10 +296,10 @@
if (cacheSerializer) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSData *cacheData = [cacheSerializer cacheDataWithImage:downloadedImage originalData:downloadedData imageURL:url];
[self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil];
[self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key cacheType:storeCacheType completion:nil];
});
} else {
[self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];
[self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key cacheType:storeCacheType completion:nil];
}
}
[self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];
@ -332,13 +323,6 @@
return operation;
}
- (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 completion:nil];
}
}
- (void)cancelAll {
@synchronized (self.runningOperations) {
NSArray<SDWebImageCombinedOperation *> *copiedOperations = [self.runningOperations copy];

View File

@ -8,6 +8,7 @@
*/
#import "SDTestCase.h"
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDAnimatedImage.h>
#import <SDWebImage/SDAnimatedImageView.h>
#import <SDWebImage/SDWebImageGIFCoder.h>

View File

@ -9,11 +9,13 @@
#import "SDTestCase.h"
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDWebImageCodersManager.h>
#import <SDWebImage/SDWebImageCachesManager.h>
#import "SDWebImageTestDecoder.h"
#import "SDMockFileManager.h"
#import "SDWebImageTestCache.h"
NSString *kImageTestKey = @"TestImageKey.jpg";
static NSString *kTestImageKeyJPEG = @"TestImageKey.jpg";
static NSString *kTestImageKeyPNG = @"TestImageKey.png";
@interface SDImageCache ()
@ -27,6 +29,14 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
@implementation SDImageCacheTests
+ (void)setUp {
[[SDWebImageCachesManager sharedManager] addCache:[SDImageCache sharedImageCache]];
}
+ (void)tearDown {
[[SDWebImageCachesManager sharedManager] removeCache:[SDImageCache sharedImageCache]];
}
- (void)test01SharedImageCache {
expect([SDImageCache sharedImageCache]).toNot.beNil();
}
@ -43,14 +53,14 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test04ClearDiskCache{
XCTestExpectation *expectation = [self expectationWithDescription:@"Clear disk cache"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[[SDImageCache sharedImageCache] calculateSizeWithCompletionBlock:^(NSUInteger fileCount, NSUInteger totalSize) {
expect(fileCount).to.equal(0);
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
@ -65,12 +75,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test05ClearMemoryCache{
XCTestExpectation *expectation = [self expectationWithDescription:@"Clear memory cache"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
[[SDImageCache sharedImageCache] clearMemory];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
@ -85,12 +95,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test06InsertionOfImage {
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey"];
UIImage *image = [self imageForTesting];
[[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
@ -104,12 +114,12 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test07InsertionOfImageForcingDiskStorage {
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=YES"];
UIImage *image = [self imageForTesting];
[[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey toDisk:YES completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:YES completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal(image);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (isInCache) {
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
} else {
@ -122,11 +132,11 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
// Testing storeImage:forKey:toDisk:NO
- (void)test08InsertionOfImageOnlyInMemory {
XCTestExpectation *expectation = [self expectationWithDescription:@"storeImage forKey toDisk=NO"];
UIImage *image = [self imageForTesting];
[[SDImageCache sharedImageCache] storeImage:image forKey:kImageTestKey toDisk:NO completion:nil];
UIImage *image = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:image forKey:kTestImageKeyJPEG toDisk:NO completion:nil];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.equal([self imageForTesting]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.equal([self testJPEGImage]);
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
if (!isInCache) {
[expectation fulfill];
} else {
@ -134,17 +144,17 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
}
}];
[[SDImageCache sharedImageCache] clearMemory];
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil();
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil();
[self waitForExpectationsWithCommonTimeout];
}
- (void)test09RetrieveImageThroughNSOperation {
XCTestExpectation *expectation = [self expectationWithDescription:@"queryCacheOperationForKey"];
UIImage *imageForTesting = [self imageForTesting];
[[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kImageTestKey completion:nil];
NSOperation *operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
UIImage *imageForTesting = [self testJPEGImage];
[[SDImageCache sharedImageCache] storeImage:imageForTesting forKey:kTestImageKeyJPEG completion:nil];
NSOperation *operation = [[SDImageCache sharedImageCache] queryCacheOperationForKey:kTestImageKeyJPEG done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) {
expect(image).to.equal(imageForTesting);
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
@ -155,10 +165,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test10RemoveImageForKeyWithCompletion {
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
@ -166,10 +176,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test11RemoveImageforKeyNotFromDiskWithCompletion{
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:NO"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey fromDisk:NO withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).toNot.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:NO withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).toNot.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
@ -177,10 +187,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test12RemoveImageforKeyFromDiskWithCompletion{
XCTestExpectation *expectation = [self expectationWithDescription:@"removeImageForKey fromDisk:YES"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey fromDisk:YES withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kImageTestKey]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey]).to.beNil;
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:nil];
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG fromDisk:YES withCompletion:^{
expect([[SDImageCache sharedImageCache] imageFromDiskCacheForKey:kTestImageKeyJPEG]).to.beNil;
expect([[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG]).to.beNil;
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
@ -192,9 +202,9 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test21InitialDiskCount{
XCTestExpectation *expectation = [self expectationWithDescription:@"getDiskCount"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
expect([[SDImageCache sharedImageCache] getDiskCount]).to.equal(1);
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
@ -202,7 +212,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
}
- (void)test31CachePathForAnyKey{
NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey];
NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG];
expect(path).toNot.beNil;
}
@ -213,10 +223,10 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test33CachePathForExistingKey{
XCTestExpectation *expectation = [self expectationWithDescription:@"cachePathForKey inPath"];
[[SDImageCache sharedImageCache] storeImage:[self imageForTesting] forKey:kImageTestKey completion:^{
NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG completion:^{
NSString *path = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG];
expect(path).notTo.beNil;
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
@ -240,24 +250,24 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
- (void)test40InsertionOfImageData {
XCTestExpectation *expectation = [self expectationWithDescription:@"Insertion of image data works"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
[[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kImageTestKey];
[[SDImageCache sharedImageCache] storeImageDataToDisk:imageData forKey:kTestImageKeyJPEG];
UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kImageTestKey];
UIImage *storedImageFromMemory = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG];
expect(storedImageFromMemory).to.equal(nil);
NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kImageTestKey];
NSString *cachePath = [[SDImageCache sharedImageCache] cachePathForKey:kTestImageKeyJPEG];
UIImage *cachedImage = [[UIImage alloc] initWithContentsOfFile:cachePath];
NSData *storedImageData = UIImageJPEGRepresentation(cachedImage, 1.0);
expect(storedImageData.length).to.beGreaterThan(0);
expect(cachedImage.size).to.equal(image.size);
// can't directly compare image and cachedImage because apparently there are some slight differences, even though the image is the same
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kImageTestKey completion:^(BOOL isInCache) {
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
expect(isInCache).to.equal(YES);
[[SDImageCache sharedImageCache] removeImageForKey:kImageTestKey withCompletion:^{
[[SDImageCache sharedImageCache] removeImageForKey:kTestImageKeyJPEG withCompletion:^{
[expectation fulfill];
}];
}];
@ -315,7 +325,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
#endif
- (void)test41StoreImageDataToDiskWithCustomFileManager {
NSData *imageData = [NSData dataWithContentsOfFile:[self testImagePath]];
NSData *imageData = [NSData dataWithContentsOfFile:[self testJPEGPath]];
NSError *targetError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteNoPermissionError userInfo:nil];
SDMockFileManager *fileManager = [[SDMockFileManager alloc] init];
@ -327,7 +337,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
// This disk cache path creation will be mocked with error.
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"test" diskCacheDirectory:@"/" config:config];
[cache storeImageDataToDisk:imageData
forKey:kImageTestKey];
forKey:kTestImageKeyJPEG];
expect(fileManager.lastError).equal(targetError);
}
@ -352,22 +362,224 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
expect([diskCache isKindOfClass:[SDWebImageTestDiskCache class]]).to.beTruthy();
}
#pragma mark - SDWebImageCache & SDWebImageCachesManager
- (void)test50SDWebImageCacheQueryOp {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache query op works"];
[[SDImageCache sharedImageCache] storeImage:[self testJPEGImage] forKey:kTestImageKeyJPEG toDisk:NO completion:nil];
[[SDWebImageCachesManager sharedManager] queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
expect(image).notTo.beNil();
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test51SDWebImageCacheStoreOp {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache store op works"];
[[SDWebImageCachesManager sharedManager] storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^{
UIImage *image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG];
expect(image).notTo.beNil();
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
expect(isInCache).to.beTruthy();
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test52SDWebImageCacheRemoveOp {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache remove op works"];
[[SDWebImageCachesManager sharedManager] removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeDisk completion:^{
UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG];
expect(memoryImage).notTo.beNil();
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
expect(isInCache).to.beFalsy();
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test53SDWebImageCacheContainsOp {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache contains op works"];
[[SDWebImageCachesManager sharedManager] containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) {
expect(containsCacheType).equal(SDImageCacheTypeMemory);
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test54SDWebImageCacheClearOp {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCache clear op works"];
[[SDWebImageCachesManager sharedManager] clearWithCacheType:SDImageCacheTypeAll completion:^{
UIImage *memoryImage = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:kTestImageKeyJPEG];
expect(memoryImage).to.beNil();
[[SDImageCache sharedImageCache] diskImageExistsWithKey:kTestImageKeyJPEG completion:^(BOOL isInCache) {
expect(isInCache).to.beFalsy();
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test55SDWebImageCachesManagerOperationPolicySimple {
SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init];
SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"];
SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"];
[cachesManager addCache:cache1];
[cachesManager addCache:cache2];
[[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil];
// LowestOnly
cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly;
cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly;
cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly;
cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly;
cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyLowestOnly;
[cachesManager queryImageForKey:kTestImageKeyJPEG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
expect(image).to.beNil();
}];
[cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:nil];
// Check Logic works, cache1 only
UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kTestImageKeyJPEG];
expect(memoryImage1).equal([self testJPEGImage]);
[cachesManager containsImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:^(SDImageCacheType containsCacheType) {
expect(containsCacheType).equal(SDImageCacheTypeMemory);
}];
[cachesManager removeImageForKey:kTestImageKeyJPEG cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil];
// HighestOnly
cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyHighestOnly;
[cachesManager queryImageForKey:kTestImageKeyPNG options:0 context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
expect(image).to.beNil();
}];
[cachesManager storeImage:[self testPNGImage] imageData:nil forKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:nil];
// Check Logic works, cache2 only
UIImage *memoryImage2 = [cache2 imageFromMemoryCacheForKey:kTestImageKeyPNG];
expect(memoryImage2).equal([self testPNGImage]);
[cachesManager containsImageForKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:^(SDImageCacheType containsCacheType) {
expect(containsCacheType).equal(SDImageCacheTypeMemory);
}];
[cachesManager removeImageForKey:kTestImageKeyPNG cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil];
}
- (void)test56SDWebImageCachesManagerOperationPolicyConcurrent {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation cocurrent policy works"];
SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init];
SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"];
SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"];
[cachesManager addCache:cache1];
[cachesManager addCache:cache2];
[[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil];
NSString *kConcurrentTestImageKey = @"kConcurrentTestImageKey";
// Cocurrent
// Check all concurrent op
cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicyConcurrent;
[cachesManager queryImageForKey:kConcurrentTestImageKey options:0 context:nil completion:nil];
[cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager removeImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil];
// Check Logic works, check cache1(memory+JPEG) & cache2(disk+PNG) at the same time. Cache1(memory) is fast and hit.
[cache1 storeImage:[self testJPEGImage] forKey:kConcurrentTestImageKey toDisk:NO completion:nil];
[cache2 storeImage:[self testPNGImage] forKey:kConcurrentTestImageKey toDisk:YES completion:^{
UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kConcurrentTestImageKey];
expect(memoryImage1).notTo.beNil();
[cache2 removeImageFromMemoryForKey:kConcurrentTestImageKey];
[cachesManager containsImageForKey:kConcurrentTestImageKey cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) {
// Cache1 hit
expect(containsCacheType).equal(SDImageCacheTypeMemory);
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test57SDWebImageCachesManagerOperationPolicySerial {
XCTestExpectation *expectation = [self expectationWithDescription:@"SDWebImageCachesManager operation serial policy works"];
SDWebImageCachesManager *cachesManager = [[SDWebImageCachesManager alloc] init];
SDImageCache *cache1 = [[SDImageCache alloc] initWithNamespace:@"cache1"];
SDImageCache *cache2 = [[SDImageCache alloc] initWithNamespace:@"cache2"];
[cachesManager addCache:cache1];
[cachesManager addCache:cache2];
[[NSFileManager defaultManager] removeItemAtPath:cache1.diskCachePath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:cache2.diskCachePath error:nil];
NSString *kSerialTestImageKey = @"kSerialTestImageKey";
// Serial
// Check all serial op
cachesManager.queryOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
cachesManager.storeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
cachesManager.removeOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
cachesManager.containsOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
cachesManager.clearOperationPolicy = SDWebImageCachesManagerOperationPolicySerial;
[cachesManager queryImageForKey:kSerialTestImageKey options:0 context:nil completion:nil];
[cachesManager storeImage:[self testJPEGImage] imageData:nil forKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager removeImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeMemory completion:nil];
[cachesManager clearWithCacheType:SDImageCacheTypeMemory completion:nil];
// Check Logic work, from cache2(disk+PNG) -> cache1(memory+JPEG). Cache2(disk) is slow but hit.
[cache1 storeImage:[self testJPEGImage] forKey:kSerialTestImageKey toDisk:NO completion:nil];
[cache2 storeImage:[self testPNGImage] forKey:kSerialTestImageKey toDisk:YES completion:^{
UIImage *memoryImage1 = [cache1 imageFromMemoryCacheForKey:kSerialTestImageKey];
expect(memoryImage1).notTo.beNil();
[cache2 removeImageFromMemoryForKey:kSerialTestImageKey];
[cachesManager containsImageForKey:kSerialTestImageKey cacheType:SDImageCacheTypeAll completion:^(SDImageCacheType containsCacheType) {
// Cache2 hit
expect(containsCacheType).equal(SDImageCacheTypeDisk);
[expectation fulfill];
}];
}];
[self waitForExpectationsWithCommonTimeout];
}
#pragma mark Helper methods
- (UIImage *)imageForTesting{
- (UIImage *)testJPEGImage {
static UIImage *reusableImage = nil;
if (!reusableImage) {
reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testImagePath]];
reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
}
return reusableImage;
}
- (NSString *)testImagePath {
- (UIImage *)testPNGImage {
static UIImage *reusableImage = nil;
if (!reusableImage) {
reusableImage = [[UIImage alloc] initWithContentsOfFile:[self testPNGPath]];
}
return reusableImage;
}
- (NSString *)testJPEGPath {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
return [testBundle pathForResource:@"TestImage" ofType:@"jpg"];
}
- (NSString *)testPNGPath {
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
return [testBundle pathForResource:@"TestImage" ofType:@"png"];
}
- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace {
NSArray<NSString *> *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
return [paths[0] stringByAppendingPathComponent:fullNamespace];

View File

@ -8,6 +8,7 @@
#import "SDTestCase.h"
#import <SDWebImage/SDWebImageManager.h>
#import <SDWebImage/SDImageCache.h>
#import "SDWebImageTestTransformer.h"
@interface SDWebImageManagerTests : SDTestCase
@ -62,32 +63,6 @@
[self waitForExpectationsWithCommonTimeout];
}
- (void)test04CachedImageExistsForURL {
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in cache"];
NSURL *imageURL = [NSURL URLWithString:kTestJpegURL];
[[SDWebImageManager sharedManager] cachedImageExistsForURL:imageURL completion:^(BOOL isInCache) {
if (isInCache) {
[expectation fulfill];
} else {
XCTFail(@"Image should be in cache");
}
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test05DiskImageExistsForURL {
__block XCTestExpectation *expectation = [self expectationWithDescription:@"Image exists in disk cache"];
NSURL *imageURL = [NSURL URLWithString:kTestJpegURL];
[[SDWebImageManager sharedManager] diskImageExistsForURL:imageURL completion:^(BOOL isInCache) {
if (isInCache) {
[expectation fulfill];
} else {
XCTFail(@"Image should be in cache");
}
}];
[self waitForExpectationsWithCommonTimeout];
}
- (void)test06CancellAll {
XCTestExpectation *expectation = [self expectationWithDescription:@"Cancel"];

View File

@ -8,6 +8,7 @@
*/
#import "SDTestCase.h"
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDWebImagePrefetcher.h>
@interface SDWebImagePrefetcherTests : SDTestCase <SDWebImagePrefetcherDelegate>

View File

@ -28,6 +28,8 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDMemoryCache.h>
#import <SDWebImage/SDDiskCache.h>
#import <SDWebImage/SDWebImageCache.h>
#import <SDWebImage/SDWebImageCachesManager.h>
#import <SDWebImage/UIView+WebCache.h>
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImage/UIImageView+HighlightedWebCache.h>