Merge branch 'master' of https://github.com/rs/SDWebImage into 5.x

* 'master' of https://github.com/rs/SDWebImage:
  Update the comments and a little enhancement for FLAnimatedImageView Category
  Use a dispatch semaphore to keep thread safe for downloader because it need the hold cancel and add procedure be thread-safe
  Add the current image/alternateImage url for NSButton category. A little code refactoring
  Update macOS demo to add a clear cache button using NSButton category
  Fix that reset alternateImage cancel the image load operation for NSButton+WebCache
  Add WebCache category for NSButton on macOS
  A little enhancement to avoid block capture the heap object
  Use a internal method to avoid thread-safe issue for file manager. Remove that checkIOQueue and add sync version exist API
  Add the image transition argument for all UIView+WebCache, make this easy for user to do some fade transition. It also reuse the current setImageBlock and make it easy to customize

# Conflicts:
#	SDWebImage.xcodeproj/project.pbxproj
#	SDWebImage/SDImageCache.h
#	SDWebImage/SDImageCache.m
#	SDWebImage/UIView+WebCache.h
#	SDWebImage/UIView+WebCache.m
#	WebImage/SDWebImage.h
This commit is contained in:
DreamPiggy 2018-01-26 22:19:55 +08:00
commit f05a1bf96f
18 changed files with 903 additions and 86 deletions

View File

@ -117,6 +117,7 @@
MyCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.customImageView.sd_imageTransition = SDWebImageTransition.fadeTransition;
}
[cell.customImageView sd_setShowActivityIndicatorView:YES];

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
@ -656,6 +657,9 @@
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="400"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="1ov-0o-Na3"/>
</connections>
</window>
<connections>
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
@ -675,23 +679,36 @@
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nbD-Cx-g7b">
<rect key="frame" x="20" y="252" width="204" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="vAn-1d-apO"/>
</imageView>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kv0-67-hkh">
<rect key="frame" x="256" y="252" width="204" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="f0P-c9-GMe"/>
</imageView>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JIp-Or-vBM">
<rect key="frame" x="20" y="116" width="204" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="NJq-m3-LlB"/>
</imageView>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="khI-tY-l0M">
<rect key="frame" x="256" y="116" width="204" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="WbV-Do-9qy"/>
</imageView>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NqE-Zi-qhY">
<rect key="frame" x="212" y="17" width="56" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" title="Clear" bezelStyle="regularSquare" alignment="center" borderStyle="border" imageScaling="proportionallyUpOrDown" inset="2" id="OYN-fG-Plb">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
</view>
<connections>
<outlet property="clearCacheButton" destination="NqE-Zi-qhY" id="eoz-cU-wWs"/>
<outlet property="imageView1" destination="nbD-Cx-g7b" id="t2R-8w-ybH"/>
<outlet property="imageView2" destination="kv0-67-hkh" id="i4k-5c-bno"/>
<outlet property="imageView3" destination="JIp-Or-vBM" id="Qcf-og-59T"/>

View File

@ -16,6 +16,7 @@
@property (weak) IBOutlet NSImageView *imageView2;
@property (weak) IBOutlet NSImageView *imageView3;
@property (weak) IBOutlet NSImageView *imageView4;
@property (weak) IBOutlet NSButton *clearCacheButton;
@end
@ -33,7 +34,23 @@
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]];
[self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp"]];
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]];
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]];
self.imageView4.wantsLayer = YES;
self.imageView4.sd_imageTransition = SDWebImageTransition.fadeTransition;
[self.imageView4 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"] placeholderImage:nil options:SDWebImageForceTransition];
self.clearCacheButton.target = self;
self.clearCacheButton.action = @selector(clearCacheButtonClicked:);
[self.clearCacheButton sd_setImageWithURL:[NSURL URLWithString:@"https://png.icons8.com/color/100/000000/delete-sign.png"]];
[self.clearCacheButton sd_setAlternateImageWithURL:[NSURL URLWithString:@"https://png.icons8.com/color/100/000000/checkmark.png"]];
}
- (void)clearCacheButtonClicked:(NSResponder *)sender {
NSButton *button = (NSButton *)sender;
button.state = NSControlStateValueOn;
[[SDImageCache sharedImageCache] clearMemory];
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
button.state = NSControlStateValueOff;
}];
}
- (void)setRepresentedObject:(id)representedObject {

View File

@ -37,6 +37,8 @@
00733A711BC4880E00A5A117 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
00733A721BC4880E00A5A117 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 321DB3602011D4D60015D2CB /* NSButton+WebCache.m */; };
321E60861F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
321E60871F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
321E60881F38E8C800405457 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 321E60841F38E8C800405457 /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -324,6 +326,18 @@
324DF4BD200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; };
324DF4BE200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; };
324DF4BF200A14DC008A84CC /* SDWebImageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */; };
325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 325312C6200F09910046BF1E /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 325312C7200F09910046BF1E /* SDWebImageTransition.m */; };
3290FA041FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
3290FA051FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
3290FA061FA478AF0047D20C /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 3290FA021FA478AF0047D20C /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -1302,6 +1316,8 @@
/* Begin PBXFileReference section */
00733A4C1BC487C000A5A117 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = "<group>"; };
321DB3602011D4D60015D2CB /* NSButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = "<group>"; };
321E60841F38E8C800405457 /* SDWebImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageCoder.h; sourceTree = "<group>"; };
321E60851F38E8C800405457 /* SDWebImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageCoder.m; sourceTree = "<group>"; };
321E60921F38E8ED00405457 /* SDWebImageImageIOCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageImageIOCoder.h; sourceTree = "<group>"; };
@ -1349,6 +1365,8 @@
323F8B3D1F38EF770092B609 /* muxread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = muxread.c; sourceTree = "<group>"; };
324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageDefine.h; sourceTree = "<group>"; };
324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageDefine.m; sourceTree = "<group>"; };
325312C6200F09910046BF1E /* SDWebImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTransition.h; sourceTree = "<group>"; };
325312C7200F09910046BF1E /* SDWebImageTransition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTransition.m; sourceTree = "<group>"; };
3290FA021FA478AF0047D20C /* SDWebImageFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageFrame.h; sourceTree = "<group>"; };
3290FA031FA478AF0047D20C /* SDWebImageFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageFrame.m; sourceTree = "<group>"; };
329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImage+WebCache.h"; path = "SDWebImage/UIImage+WebCache.h"; sourceTree = "<group>"; };
@ -1659,6 +1677,8 @@
children = (
329A18571FFF5DFD008C9A2F /* UIImage+WebCache.h */,
329A18581FFF5DFD008C9A2F /* UIImage+WebCache.m */,
321DB35F2011D4D60015D2CB /* NSButton+WebCache.h */,
321DB3602011D4D60015D2CB /* NSButton+WebCache.m */,
535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */,
535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */,
53922D93148C56230056699D /* UIButton+WebCache.h */,
@ -1834,6 +1854,8 @@
53922D92148C56230056699D /* SDWebImagePrefetcher.m */,
324DF4B2200A14DC008A84CC /* SDWebImageDefine.h */,
324DF4B3200A14DC008A84CC /* SDWebImageDefine.m */,
325312C6200F09910046BF1E /* SDWebImageTransition.h */,
325312C7200F09910046BF1E /* SDWebImageTransition.m */,
);
name = Utils;
sourceTree = "<group>";
@ -2063,6 +2085,7 @@
80377C481F2F666300F89830 /* bit_reader_utils.h in Headers */,
80377C511F2F666300F89830 /* huffman_encode_utils.h in Headers */,
00733A6B1BC4880E00A5A117 /* NSData+ImageContentType.h in Headers */,
325312CB200F09910046BF1E /* SDWebImageTransition.h in Headers */,
323F8C111F38EF770092B609 /* muxi.h in Headers */,
80377EC41F2F66D500F89830 /* vp8li_dec.h in Headers */,
00733A6A1BC4880E00A5A117 /* SDWebImagePrefetcher.h in Headers */,
@ -2133,6 +2156,7 @@
80377EA11F2F66D400F89830 /* vp8_dec.h in Headers */,
80377C271F2F666300F89830 /* rescaler_utils.h in Headers */,
323F8B511F38EF770092B609 /* backward_references_enc.h in Headers */,
325312C9200F09910046BF1E /* SDWebImageTransition.h in Headers */,
43A918651D8308FE00B3925F /* SDImageCacheConfig.h in Headers */,
4314D1741D0E0E3B004B36C9 /* types.h in Headers */,
4314D1761D0E0E3B004B36C9 /* decode.h in Headers */,
@ -2211,6 +2235,7 @@
431BB6E91D06D2C1006A3455 /* SDWebImageDownloaderOperation.h in Headers */,
80377ED41F2F66D500F89830 /* vp8li_dec.h in Headers */,
431BB6EB1D06D2C1006A3455 /* UIView+WebCacheOperation.h in Headers */,
325312CC200F09910046BF1E /* SDWebImageTransition.h in Headers */,
80377C6D1F2F666400F89830 /* huffman_utils.h in Headers */,
80377C731F2F666400F89830 /* random_utils.h in Headers */,
431BB6EE1D06D2C1006A3455 /* NSData+ImageContentType.h in Headers */,
@ -2316,10 +2341,12 @@
321E60C31F38E91700405457 /* UIImage+ForceDecode.h in Headers */,
80377E561F2F66A800F89830 /* lossless_common.h in Headers */,
4397D2E91D0DDD8C00BB2784 /* UIImage+WebP.h in Headers */,
325312CD200F09910046BF1E /* SDWebImageTransition.h in Headers */,
4397D2EA1D0DDD8C00BB2784 /* UIImage+GIF.h in Headers */,
321E60B51F38E90100405457 /* SDWebImageWebPCoder.h in Headers */,
4397D2EB1D0DDD8C00BB2784 /* NSData+ImageContentType.h in Headers */,
80377C851F2F666400F89830 /* huffman_encode_utils.h in Headers */,
321DB3612011D4D70015D2CB /* NSButton+WebCache.h in Headers */,
807A122D1F89636300EC2A9B /* SDWebImageCodersManager.h in Headers */,
4397D2ED1D0DDD8C00BB2784 /* mux_types.h in Headers */,
80377C831F2F666400F89830 /* filters_utils.h in Headers */,
@ -2380,6 +2407,7 @@
80377C2E1F2F666300F89830 /* bit_reader_utils.h in Headers */,
80377C371F2F666300F89830 /* huffman_encode_utils.h in Headers */,
4A2CAE2F1AB4BB7500B6BC39 /* UIImage+MultiFormat.h in Headers */,
325312CA200F09910046BF1E /* SDWebImageTransition.h in Headers */,
323F8C101F38EF770092B609 /* muxi.h in Headers */,
80377EB41F2F66D400F89830 /* vp8li_dec.h in Headers */,
4A2CAE1A1AB4BB6400B6BC39 /* SDWebImageOperation.h in Headers */,
@ -2420,6 +2448,7 @@
431738BF1CDFC2660008FEB9 /* encode.h in Headers */,
53761316155AD0D5005750A4 /* SDImageCache.h in Headers */,
323F8C0E1F38EF770092B609 /* muxi.h in Headers */,
325312C8200F09910046BF1E /* SDWebImageTransition.h in Headers */,
321E60A21F38E8F600405457 /* SDWebImageGIFCoder.h in Headers */,
5D5B9142188EE8DD006D06BD /* NSData+ImageContentType.h in Headers */,
80377BFE1F2F665300F89830 /* color_cache_utils.h in Headers */,
@ -2772,6 +2801,7 @@
323F8B991F38EF770092B609 /* near_lossless_enc.c in Sources */,
80377DE81F2F66A700F89830 /* yuv_mips_dsp_r2.c in Sources */,
80377EC31F2F66D500F89830 /* vp8l_dec.c in Sources */,
325312D1200F09910046BF1E /* SDWebImageTransition.m in Sources */,
321E609D1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */,
323F8B9F1F38EF770092B609 /* picture_csp_enc.c in Sources */,
43C892A31D9D6DDD0022038D /* demux.c in Sources */,
@ -2936,6 +2966,7 @@
323F8B451F38EF770092B609 /* analysis_enc.c in Sources */,
80377C261F2F666300F89830 /* rescaler_utils.c in Sources */,
323F8BBB1F38EF770092B609 /* predictor_enc.c in Sources */,
325312CF200F09910046BF1E /* SDWebImageTransition.m in Sources */,
80377D2F1F2F66A700F89830 /* dec_msa.c in Sources */,
323F8C151F38EF770092B609 /* muxinternal.c in Sources */,
80377D571F2F66A700F89830 /* rescaler_sse2.c in Sources */,
@ -3082,6 +3113,7 @@
80377C6A1F2F666400F89830 /* huffman_encode_utils.c in Sources */,
323F8B481F38EF770092B609 /* analysis_enc.c in Sources */,
80377DFE1F2F66A800F89830 /* dec_msa.c in Sources */,
325312D2200F09910046BF1E /* SDWebImageTransition.m in Sources */,
323F8BBE1F38EF770092B609 /* predictor_enc.c in Sources */,
80377E261F2F66A800F89830 /* rescaler_sse2.c in Sources */,
323F8C181F38EF770092B609 /* muxinternal.c in Sources */,
@ -3233,6 +3265,7 @@
80377C8C1F2F666400F89830 /* random_utils.c in Sources */,
323F8BAD1F38EF770092B609 /* picture_psnr_enc.c in Sources */,
323F8BC51F38EF770092B609 /* quant_enc.c in Sources */,
321DB3622011D4D70015D2CB /* NSButton+WebCache.m in Sources */,
80377C7F1F2F666400F89830 /* color_cache_utils.c in Sources */,
80377E331F2F66A800F89830 /* alpha_processing_neon.c in Sources */,
80377E401F2F66A800F89830 /* dec_clip_tables.c in Sources */,
@ -3274,6 +3307,7 @@
43A918701D8308FE00B3925F /* SDImageCacheConfig.m in Sources */,
80377E4B1F2F66A800F89830 /* enc_mips32.c in Sources */,
4397D2AB1D0DDD8C00BB2784 /* UIView+WebCacheOperation.m in Sources */,
325312D3200F09910046BF1E /* SDWebImageTransition.m in Sources */,
80377E391F2F66A800F89830 /* argb.c in Sources */,
4369C2831D9807EC007E863A /* UIView+WebCache.m in Sources */,
80377E611F2F66A800F89830 /* lossless_sse2.c in Sources */,
@ -3361,6 +3395,7 @@
323F8B981F38EF770092B609 /* near_lossless_enc.c in Sources */,
80377D6F1F2F66A700F89830 /* cost.c in Sources */,
80377EB31F2F66D400F89830 /* vp8l_dec.c in Sources */,
325312D0200F09910046BF1E /* SDWebImageTransition.m in Sources */,
321E609C1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */,
323F8B9E1F38EF770092B609 /* picture_csp_enc.c in Sources */,
80377D9E1F2F66A700F89830 /* upsampling_mips_dsp_r2.c in Sources */,
@ -3511,6 +3546,7 @@
80377CE51F2F66A100F89830 /* cost.c in Sources */,
80377E931F2F66D000F89830 /* vp8l_dec.c in Sources */,
321E609A1F38E8ED00405457 /* SDWebImageImageIOCoder.m in Sources */,
325312CE200F09910046BF1E /* SDWebImageTransition.m in Sources */,
323F8B9C1F38EF770092B609 /* picture_csp_enc.c in Sources */,
80377D141F2F66A100F89830 /* upsampling_mips_dsp_r2.c in Sources */,
80377D191F2F66A100F89830 /* yuv_mips_dsp_r2.c in Sources */,

View File

@ -72,23 +72,27 @@
operationKey:nil
setImageBlock:^(UIImage *image, NSData *imageData) {
SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:imageData];
__block FLAnimatedImage *animatedImage = image.sd_FLAnimatedImage;
// We could not directlly create the animated image on bacakground queue because it's time consuming, by the time we set it back, the current runloop has passed and the placeholder has been rendered and then replaced with animated image, this cause a flashing.
// Previously we use a trick to firstly set the static poster image, then set animated image back to avoid flashing, but this trick fail when using with UIView transition because it's based on the Core Animation. Core Animation will capture the current layer state to do rendering, so even we later set it back, the transition will not update
// Previously we use a trick to firstly set the static poster image, then set animated image back to avoid flashing, but this trick fail when using with UIView transition because it's based on the Core Animation. Core Animation will capture the current layer state to do rendering, so even we later set it back, the transition will not update. (it's recommended to use `SDWebImageTransition` instead)
// So we have no choice to force store the FLAnimatedImage into memory cache using a associated object binding to UIImage instance. This consumed memory is adoptable and much smaller than `_UIAnimatedImage` for big GIF
if (animatedImage || imageFormat == SDImageFormatGIF) {
if (animatedImage) {
weakSelf.animatedImage = animatedImage;
FLAnimatedImage *associatedAnimatedImage = image.sd_FLAnimatedImage;
if (associatedAnimatedImage || imageFormat == SDImageFormatGIF) {
if (associatedAnimatedImage) {
weakSelf.animatedImage = associatedAnimatedImage;
weakSelf.image = nil;
if (group) {
dispatch_group_leave(group);
}
} else {
// Firstly set the static poster image to avoid flashing
UIImage *posterImage = image.images ? image.images.firstObject : image;
weakSelf.image = posterImage;
weakSelf.animatedImage = nil;
// The imageData should not be nil, create FLAnimatedImage in global queue because it's time consuming, then set it back
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
animatedImage = [FLAnimatedImage animatedImageWithGIFData:imageData];
image.sd_FLAnimatedImage = animatedImage;
FLAnimatedImage *animatedImage = [FLAnimatedImage animatedImageWithGIFData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
image.sd_FLAnimatedImage = animatedImage;
weakSelf.animatedImage = animatedImage;
weakSelf.image = nil;
if (group) {

View File

@ -0,0 +1,259 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#if SD_MAC
#import "SDWebImageManager.h"
@interface NSButton (WebCache)
#pragma mark - Image
/**
* Get the current image URL.
*/
- (nullable NSURL *)sd_currentImageURL;
/**
* Set the button `image` with an `url`.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
/**
* Set the button `image` with an `url` and a placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @see sd_setImageWithURL:placeholderImage:options:
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
/**
* Set the button `image` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
/**
* Set the button `image` with an `url`.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Set the button `image` with an `url`, placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
/**
* Set the button `image` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Set the button `image` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
* @param progressBlock A block called while image is downloading
* @note the progress block is executed on a background queue
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
#pragma mark - Alternate Image
/**
* Get the current alternateImage URL.
*/
- (nullable NSURL *)sd_currentAlternateImageURL;
/**
* Set the button `alternateImage` with an `url`.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
/**
* Set the button `alternateImage` with an `url` and a placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
* @see sd_setAlternateImageWithURL:placeholderImage:options:
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
/**
* Set the button `alternateImage` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
* @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
/**
* Set the button `alternateImage` with an `url`.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the alternateImage parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the alternateImage was retrieved from the local cache or from the network.
* The fourth parameter is the original alternateImage url.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Set the button `alternateImage` with an `url`, placeholder.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the alternateImage parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the alternateImage was retrieved from the local cache or from the network.
* The fourth parameter is the original alternateImage url.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
/**
* Set the button `alternateImage` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
* @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the alternateImage parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the alternateImage was retrieved from the local cache or from the network.
* The fourth parameter is the original alternateImage url.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
/**
* Set the button `alternateImage` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the alternateImage.
* @param placeholder The alternateImage to be set initially, until the alternateImage request finishes.
* @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values.
* @param progressBlock A block called while alternateImage is downloading
* @note the progress block is executed on a background queue
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the alternateImage parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the alternateImage was retrieved from the local cache or from the network.
* The fourth parameter is the original alternateImage url.
*/
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
#pragma mark - Cancel
/**
* Cancel the current image download
*/
- (void)sd_cancelCurrentImageLoad;
/**
* Cancel the current alternateImage download
*/
- (void)sd_cancelCurrentAlternateImageLoad;
@end
#endif

View File

@ -0,0 +1,147 @@
/*
* 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 "NSButton+WebCache.h"
#if SD_MAC
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
#import "UIView+WebCache.h"
static inline NSString * imageOperationKey() {
return @"NSButtonImageOperation";
}
static inline NSString * alternateImageOperationKey() {
return @"NSButtonAlternateImageOperation";
}
@implementation NSButton (WebCache)
#pragma mark - Image
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentImageURL = url;
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:imageOperationKey()
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
weakSelf.image = image;
}
progress:progressBlock
completed:completedBlock];
}
#pragma mark - Alternate Image
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url {
[self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentAlternateImageURL = url;
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:alternateImageOperationKey()
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
weakSelf.alternateImage = image;
}
progress:progressBlock
completed:completedBlock];
}
#pragma mark - Cancel
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:imageOperationKey()];
}
- (void)sd_cancelCurrentAlternateImageLoad {
[self sd_cancelImageLoadOperationWithKey:alternateImageOperationKey()];
}
#pragma mar - Private
- (NSURL *)sd_currentImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentImageURL));
}
- (void)setSd_currentImageURL:(NSURL *)sd_currentImageURL {
objc_setAssociatedObject(self, @selector(sd_currentImageURL), sd_currentImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSURL *)sd_currentAlternateImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentAlternateImageURL));
}
- (void)setSd_currentAlternateImageURL:(NSURL *)sd_currentAlternateImageURL {
objc_setAssociatedObject(self, @selector(sd_currentAlternateImageURL), sd_currentAlternateImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
#endif

View File

@ -207,7 +207,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
}
data = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:format];
}
[self safeStoreImageDataToDisk:data forKey:key error:&writeError];
[self _storeImageDataToDisk:data forKey:key error:&writeError];
}
if (completionBlock) {
@ -236,16 +236,15 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
__block BOOL success = YES;
void(^storeImageDataBlock)(void) = ^{
success = [self safeStoreImageDataToDisk:imageData forKey:key error:error];
success = [self _storeImageDataToDisk:imageData forKey:key error:error];
};
dispatch_sync(self.ioQueue, storeImageDataBlock);
return success;
}
- (BOOL)safeStoreImageDataToDisk:(nullable NSData *)imageData
forKey:(nullable NSString *)key
error:(NSError * _Nullable __autoreleasing * _Nonnull)error {
// Make sure to call form io queue by caller
- (BOOL)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key error:(NSError * _Nullable __autoreleasing * _Nonnull)error {
if (!imageData || !key) {
return NO;
}
@ -278,9 +277,8 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
#pragma mark - Query and Retrieve Ops
- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock {
dispatch_async(_ioQueue, ^{
BOOL exists = [self diskImageDataExistsWithKey:key];
dispatch_async(self.ioQueue, ^{
BOOL exists = [self _diskImageDataExistsWithKey:key];
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(exists);
@ -293,6 +291,20 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
if (!key) {
return NO;
}
__block BOOL exists = NO;
dispatch_sync(self.ioQueue, ^{
exists = [self _diskImageDataExistsWithKey:key];
});
return exists;
}
// Make sure to call form io queue by caller
- (BOOL)_diskImageDataExistsWithKey:(nullable NSString *)key {
if (!key) {
return NO;
}
BOOL exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]];
// fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name

View File

@ -9,6 +9,9 @@
#import "SDWebImageDownloader.h"
#import "SDWebImageDownloaderOperation.h"
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
@interface SDWebImageDownloadToken ()
@property (nonatomic, weak, nullable) NSOperation<SDWebImageDownloaderOperationInterface> *downloadOperation;
@ -36,6 +39,7 @@
@property (assign, nonatomic, nullable) Class operationClass;
@property (strong, nonatomic, nonnull) NSMutableDictionary<NSURL *, SDWebImageDownloaderOperation *> *URLOperations;
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;
@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe
// The session in which data tasks will run
@property (strong, nonatomic) NSURLSession *session;
@ -94,6 +98,7 @@
#else
_HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
#endif
_operationsLock = dispatch_semaphore_create(1);
_downloadTimeout = 15.0;
[self createNewSessionWithConfiguration:sessionConfiguration];
@ -238,11 +243,15 @@
if (!url) {
return;
}
SDWebImageDownloaderOperation *operation = [self operationForURL:url];
BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
if (canceled) {
[self removeOperationForURL:url];
LOCK(self.operationsLock);
SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
if (operation) {
BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
if (canceled) {
[self.URLOperations removeObjectForKey:url];
}
}
UNLOCK(self.operationsLock);
}
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
@ -257,17 +266,24 @@
return nil;
}
SDWebImageDownloaderOperation *operation = [self operationForURL:url];
LOCK(self.operationsLock);
SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
if (!operation) {
operation = createCallback();
[self setOperation:operation forURL:url];
__weak typeof(self) wself = self;
operation.completionBlock = ^{
__strong typeof(wself) sself = wself;
[sself removeOperationForURL:url];
if (!sself) {
return;
}
LOCK(sself.operationsLock);
[sself.URLOperations removeObjectForKey:url];
UNLOCK(sself.operationsLock);
};
[self.URLOperations setObject:operation forKey:url];
}
UNLOCK(self.operationsLock);
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
SDWebImageDownloadToken *token = [SDWebImageDownloadToken new];
@ -288,35 +304,6 @@
#pragma mark Helper methods
- (SDWebImageDownloaderOperation *)operationForURL:(NSURL *)url {
if (!url) {
return nil;
}
SDWebImageDownloaderOperation *operation;
@synchronized (self.URLOperations) {
operation = [self.URLOperations objectForKey:url];
}
return operation;
}
- (void)setOperation:(SDWebImageDownloaderOperation *)operation forURL:(NSURL *)url {
if (!operation || !url) {
return;
}
@synchronized (self.URLOperations) {
[self.URLOperations setObject:operation forKey:url];
}
}
- (void)removeOperationForURL:(NSURL *)url {
if (!url) {
return;
}
@synchronized (self.URLOperations) {
[self.URLOperations removeObjectForKey:url];
}
}
- (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task {
SDWebImageDownloaderOperation *returnOperation = nil;
for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) {

View File

@ -111,7 +111,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only.
*/
SDWebImageFromCacheOnly = 1 << 15
SDWebImageFromCacheOnly = 1 << 15,
/**
* By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well.
*/
SDWebImageForceTransition = 1 << 16
};
typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL);

View File

@ -0,0 +1,97 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#if SD_UIKIT || SD_MAC
#import "SDImageCache.h"
// for UIKit(iOS & tvOS), we use `+[UIView transitionWithView:duration:options:animations:completion]` for transition animations.
// for AppKit(macOS), we use `+[NSAnimationContext runAnimationGroup:completionHandler:]` for transition animations. You can call `+[NSAnimationContext currentContext]` to grab the context during animations block.
// These transition are provided for basic usage. If you need complicated animation, consider to directly use Core Animation or use `SDWebImageAvoidAutoSetImage` and implement your own after image load finished.
#if SD_UIKIT
typedef UIViewAnimationOptions SDWebImageAnimationOptions;
#else
typedef NS_OPTIONS(NSUInteger, SDWebImageAnimationOptions) {
SDWebImageAnimationOptionAllowsImplicitAnimation = 1 << 0, // specify `allowsImplicitAnimation` for the `NSAnimationContext`
};
#endif
typedef void (^SDWebImageTransitionPreparesBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL);
typedef void (^SDWebImageTransitionAnimationsBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image);
typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished);
@interface SDWebImageTransition : NSObject
/**
By default, we set the image to the view at the beginning of the animtions. You can disable this and provide custom set image process
*/
@property (nonatomic, assign) BOOL avoidAutoSetImage;
/**
The duration of the transition animation, measured in seconds. Defaults to 0.5.
*/
@property (nonatomic, assign) NSTimeInterval duration;
/**
The timing function used for all animations within this transition animation (macOS).
*/
@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction NS_AVAILABLE_MAC(10_7);
/**
A mask of options indicating how you want to perform the animations.
*/
@property (nonatomic, assign) SDWebImageAnimationOptions animationOptions;
/**
A block object to be executed before the animation sequence starts.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionPreparesBlock prepares;
/**
A block object that contains the changes you want to make to the specified view.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionAnimationsBlock animations;
/**
A block object to be executed when the animation sequence ends.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionCompletionBlock completion;
@end
// Convenience way to create transition. Remember to specify the duration
// for UIKit, these transition just use the correspond `animationOptions`
// for AppKit, these transition use Core Animation in `animations`. So your view must be layer-backed. Set `wantsLayer = YES` before you apply it.
@interface SDWebImageTransition (Conveniences)
// class property is available in Xcode 8. We will drop the Xcode 7.3 support in 5.x
#if __has_feature(objc_class_property)
/// Fade transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *fadeTransition;
/// Flip from left transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromLeftTransition;
/// Flip from right transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromRightTransition;
/// Flip from top transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromTopTransition;
/// Flip from bottom transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromBottomTransition;
/// Curl up transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlUpTransition;
/// Curl down transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlDownTransition;
#else
+ (nonnull instancetype)fadeTransition;
+ (nonnull instancetype)flipFromLeftTransition;
+ (nonnull instancetype)flipFromRightTransition;
+ (nonnull instancetype)flipFromTopTransition;
+ (nonnull instancetype)flipFromBottomTransition;
+ (nonnull instancetype)curlUpTransition;
+ (nonnull instancetype)curlDownTransition;
#endif
@end
#endif

View File

@ -0,0 +1,137 @@
/*
* 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 "SDWebImageTransition.h"
#if SD_UIKIT || SD_MAC
#if SD_MAC
#import <QuartzCore/QuartzCore.h>
#endif
@implementation SDWebImageTransition
- (instancetype)init {
self = [super init];
if (self) {
self.duration = 0.5;
}
return self;
}
@end
@implementation SDWebImageTransition (Conveniences)
+ (SDWebImageTransition *)fadeTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCrossDissolve;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionFade;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromLeftTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromLeft;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromLeft;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromRightTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromRight;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromRight;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromTopTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromTop;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromBottomTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromBottom;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)curlUpTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlUp;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)curlDownTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlDown;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
@end
#endif

View File

@ -128,7 +128,7 @@
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
#pragma mark - Background image
#pragma mark - Background Image
/**
* Get the current background image URL.

View File

@ -26,22 +26,30 @@ static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"backgroundImage_%lu", (unsigned long)state];
}
static inline NSString * imageOperationKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"UIButtonImageOperation%lu", (unsigned long)state];
}
static inline NSString * backgroundImageOperationKeyForState(UIControlState state) {
return [NSString stringWithFormat:@"UIButtonBackgroundImageOperation%lu", (unsigned long)state];
}
@implementation UIButton (WebCache)
#pragma mark - Image
- (nullable NSURL *)sd_currentImageURL {
NSURL *url = self.imageURLStorage[imageURLKeyForState(self.state)];
NSURL *url = self.sd_imageURLStorage[imageURLKeyForState(self.state)];
if (!url) {
url = self.imageURLStorage[imageURLKeyForState(UIControlStateNormal)];
url = self.sd_imageURLStorage[imageURLKeyForState(UIControlStateNormal)];
}
return url;
}
- (nullable NSURL *)sd_imageURLForState:(UIControlState)state {
return self.imageURLStorage[imageURLKeyForState(state)];
return self.sd_imageURLStorage[imageURLKeyForState(state)];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
@ -70,16 +78,16 @@ static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock {
if (!url) {
[self.imageURLStorage removeObjectForKey:imageURLKeyForState(state)];
[self.sd_imageURLStorage removeObjectForKey:imageURLKeyForState(state)];
} else {
self.imageURLStorage[imageURLKeyForState(state)] = url;
self.sd_imageURLStorage[imageURLKeyForState(state)] = url;
}
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]
operationKey:imageOperationKeyForState(state)
setImageBlock:^(UIImage *image, NSData *imageData) {
[weakSelf setImage:image forState:state];
}
@ -87,20 +95,20 @@ static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
completed:completedBlock];
}
#pragma mark - Background image
#pragma mark - Background Image
- (nullable NSURL *)sd_currentBackgroundImageURL {
NSURL *url = self.imageURLStorage[backgroundImageURLKeyForState(self.state)];
NSURL *url = self.sd_imageURLStorage[backgroundImageURLKeyForState(self.state)];
if (!url) {
url = self.imageURLStorage[backgroundImageURLKeyForState(UIControlStateNormal)];
url = self.sd_imageURLStorage[backgroundImageURLKeyForState(UIControlStateNormal)];
}
return url;
}
- (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state {
return self.imageURLStorage[backgroundImageURLKeyForState(state)];
return self.sd_imageURLStorage[backgroundImageURLKeyForState(state)];
}
- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state {
@ -129,16 +137,16 @@ static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock {
if (!url) {
[self.imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)];
[self.sd_imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)];
} else {
self.imageURLStorage[backgroundImageURLKeyForState(state)] = url;
self.sd_imageURLStorage[backgroundImageURLKeyForState(state)] = url;
}
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]
operationKey:backgroundImageOperationKeyForState(state)
setImageBlock:^(UIImage *image, NSData *imageData) {
[weakSelf setBackgroundImage:image forState:state];
}
@ -146,15 +154,19 @@ static inline NSString * backgroundImageURLKeyForState(UIControlState state) {
completed:completedBlock];
}
#pragma mark - Cancel
- (void)sd_cancelImageLoadForState:(UIControlState)state {
[self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]];
[self sd_cancelImageLoadOperationWithKey:imageOperationKeyForState(state)];
}
- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state {
[self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]];
[self sd_cancelImageLoadOperationWithKey:backgroundImageOperationKeyForState(state)];
}
- (SDStateImageURLDictionary *)imageURLStorage {
#pragma mark - Private
- (SDStateImageURLDictionary *)sd_imageURLStorage {
SDStateImageURLDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey);
if (!storage) {
storage = [NSMutableDictionary dictionary];

View File

@ -12,6 +12,7 @@
#import "SDWebImageDefine.h"
#import "SDWebImageManager.h"
#import "SDWebImageTransition.h"
/**
The value specify that the image progress unit count cannot be determined because the progressBlock is not been called.
@ -97,6 +98,14 @@ typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable ima
*/
- (void)sd_cancelCurrentImageLoad;
#pragma mark - Image Transition
/**
The image transition when image load finished. See `SDWebImageTransition`.
If you specify nil, do not do transition. Defautls to nil.
*/
@property (nonatomic, strong, nullable) SDWebImageTransition *sd_imageTransition;
#if SD_UIKIT
#pragma mark - Activity indicator

View File

@ -145,11 +145,17 @@ static char TAG_ACTIVITY_SHOW;
targetData = nil;
}
// check whether we should use the image transition
SDWebImageTransition *transition = nil;
if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) {
transition = sself.sd_imageTransition;
}
if ([context valueForKey:SDWebImageContextSetImageGroup]) {
dispatch_group_t group = [context valueForKey:SDWebImageContextSetImageGroup];
dispatch_group_enter(group);
dispatch_main_async_safe(^{
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
});
// ensure completion block is called after custom setImage process finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
@ -157,7 +163,7 @@ static char TAG_ACTIVITY_SHOW;
});
} else {
dispatch_main_async_safe(^{
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
callCompletedBlockClojure();
});
}
@ -179,24 +185,79 @@ static char TAG_ACTIVITY_SHOW;
}
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock {
[self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:0 imageURL:nil];
}
- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock transition:(SDWebImageTransition *)transition cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL {
UIView *view = self;
SDSetImageBlock finalSetImageBlock;
if (setImageBlock) {
setImageBlock(image, imageData);
return;
finalSetImageBlock = setImageBlock;
}
#if SD_UIKIT || SD_MAC
if ([self isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = (UIImageView *)self;
imageView.image = image;
else if ([view isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = (UIImageView *)view;
finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData) {
imageView.image = setImage;
};
}
#endif
#if SD_UIKIT
else if ([view isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)view;
finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData){
[button setImage:setImage forState:UIControlStateNormal];
};
}
#endif
if (transition) {
#if SD_UIKIT
if ([self isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)self;
[button setImage:image forState:UIControlStateNormal];
}
[UIView transitionWithView:view duration:0 options:0 animations:^{
// 0 duration to let UIKit render placeholder and prepares block
if (transition.prepares) {
transition.prepares(view, image, imageData, cacheType, imageURL);
}
} completion:^(BOOL finished) {
[UIView transitionWithView:view duration:transition.duration options:transition.animationOptions animations:^{
if (finalSetImageBlock && !transition.avoidAutoSetImage) {
finalSetImageBlock(image, imageData);
}
if (transition.animations) {
transition.animations(view, image);
}
} completion:transition.completion];
}];
#elif SD_MAC
[NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull prepareContext) {
// 0 duration to let AppKit render placeholder and prepares block
prepareContext.duration = 0;
if (transition.prepares) {
transition.prepares(view, image, imageData, cacheType, imageURL);
}
} completionHandler:^{
[NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
context.duration = transition.duration;
context.timingFunction = transition.timingFunction;
context.allowsImplicitAnimation = (transition.animationOptions & SDWebImageAnimationOptionAllowsImplicitAnimation);
if (finalSetImageBlock && !transition.avoidAutoSetImage) {
finalSetImageBlock(image, imageData);
}
if (transition.animations) {
transition.animations(view, image);
}
} completionHandler:^{
if (transition.completion) {
transition.completion(YES);
}
}];
}];
#endif
} else {
if (finalSetImageBlock) {
finalSetImageBlock(image, imageData);
}
}
}
- (void)sd_setNeedsLayout {
@ -207,6 +268,15 @@ static char TAG_ACTIVITY_SHOW;
#endif
}
#pragma mark - Image Transition
- (SDWebImageTransition *)sd_imageTransition {
return objc_getAssociatedObject(self, @selector(sd_imageTransition));
}
- (void)setSd_imageTransition:(SDWebImageTransition *)sd_imageTransition {
objc_setAssociatedObject(self, @selector(sd_imageTransition), sd_imageTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark - Activity indicator
#pragma mark -

View File

@ -35,6 +35,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#import <SDWebImage/UIImage+MultiFormat.h>
#import <SDWebImage/SDWebImageOperation.h>
#import <SDWebImage/SDWebImageDownloader.h>
#import <SDWebImage/SDWebImageTransition.h>
#if SD_MAC || SD_UIKIT
#import <SDWebImage/MKAnnotationView+WebCache.h>
@ -55,6 +56,7 @@ FOUNDATION_EXPORT const unsigned char WebImageVersionString[];
#if SD_MAC
#import <SDWebImage/NSImage+Additions.h>
#import <SDWebImage/NSButton+WebCache.h>
#endif
#if SD_UIKIT