/TreasureBox/Pods/YYKit/YYKit/Image/Categories/UIImageView+YYWebImage.m

https://gitlab.com/chenguibang/TreasureBox · Objective C · 358 lines · 302 code · 40 blank · 16 comment · 58 complexity · 4f20ecaa1ff1b8f13a13af04fed19394 MD5 · raw file

  1. //
  2. // UIImageView+YYWebImage.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 15/2/23.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import "UIImageView+YYWebImage.h"
  12. #import "YYWebImageOperation.h"
  13. #import "_YYWebImageSetter.h"
  14. #import "YYKitMacro.h"
  15. #import <objc/runtime.h>
  16. YYSYNTH_DUMMY_CLASS(UIImageView_YYWebImage)
  17. static int _YYWebImageSetterKey;
  18. static int _YYWebImageHighlightedSetterKey;
  19. @implementation UIImageView (YYWebImage)
  20. #pragma mark - image
  21. - (NSURL *)imageURL {
  22. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey);
  23. return setter.imageURL;
  24. }
  25. /*
  26. "setImageWithURL" is conflict to AFNetworking and SDWebImage...WTF!
  27. So.. We use "setImageURL:" instead.
  28. */
  29. - (void)setImageURL:(NSURL *)imageURL {
  30. [self setImageWithURL:imageURL
  31. placeholder:nil
  32. options:kNilOptions
  33. manager:nil
  34. progress:nil
  35. transform:nil
  36. completion:nil];
  37. }
  38. - (void)setImageWithURL:(NSURL *)imageURL placeholder:(UIImage *)placeholder {
  39. [self setImageWithURL:imageURL
  40. placeholder:placeholder
  41. options:kNilOptions
  42. manager:nil
  43. progress:nil
  44. transform:nil
  45. completion:nil];
  46. }
  47. - (void)setImageWithURL:(NSURL *)imageURL options:(YYWebImageOptions)options {
  48. [self setImageWithURL:imageURL
  49. placeholder:nil
  50. options:options
  51. manager:nil
  52. progress:nil
  53. transform:nil
  54. completion:nil];
  55. }
  56. - (void)setImageWithURL:(NSURL *)imageURL
  57. placeholder:(UIImage *)placeholder
  58. options:(YYWebImageOptions)options
  59. completion:(YYWebImageCompletionBlock)completion {
  60. [self setImageWithURL:imageURL
  61. placeholder:placeholder
  62. options:options
  63. manager:nil
  64. progress:nil
  65. transform:nil
  66. completion:completion];
  67. }
  68. - (void)setImageWithURL:(NSURL *)imageURL
  69. placeholder:(UIImage *)placeholder
  70. options:(YYWebImageOptions)options
  71. progress:(YYWebImageProgressBlock)progress
  72. transform:(YYWebImageTransformBlock)transform
  73. completion:(YYWebImageCompletionBlock)completion {
  74. [self setImageWithURL:imageURL
  75. placeholder:placeholder
  76. options:options
  77. manager:nil
  78. progress:progress
  79. transform:transform
  80. completion:completion];
  81. }
  82. - (void)setImageWithURL:(NSURL *)imageURL
  83. placeholder:(UIImage *)placeholder
  84. options:(YYWebImageOptions)options
  85. manager:(YYWebImageManager *)manager
  86. progress:(YYWebImageProgressBlock)progress
  87. transform:(YYWebImageTransformBlock)transform
  88. completion:(YYWebImageCompletionBlock)completion {
  89. if ([imageURL isKindOfClass:[NSString class]]) imageURL = [NSURL URLWithString:(id)imageURL];
  90. manager = manager ? manager : [YYWebImageManager sharedManager];
  91. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey);
  92. if (!setter) {
  93. setter = [_YYWebImageSetter new];
  94. objc_setAssociatedObject(self, &_YYWebImageSetterKey, setter, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  95. }
  96. int32_t sentinel = [setter cancelWithNewURL:imageURL];
  97. dispatch_async_on_main_queue(^{
  98. if ((options & YYWebImageOptionSetImageWithFadeAnimation) &&
  99. !(options & YYWebImageOptionAvoidSetImage)) {
  100. if (!self.highlighted) {
  101. [self.layer removeAnimationForKey:_YYWebImageFadeAnimationKey];
  102. }
  103. }
  104. if (!imageURL) {
  105. if (!(options & YYWebImageOptionIgnorePlaceHolder)) {
  106. self.image = placeholder;
  107. }
  108. return;
  109. }
  110. // get the image from memory as quickly as possible
  111. UIImage *imageFromMemory = nil;
  112. if (manager.cache &&
  113. !(options & YYWebImageOptionUseNSURLCache) &&
  114. !(options & YYWebImageOptionRefreshImageCache)) {
  115. imageFromMemory = [manager.cache getImageForKey:[manager cacheKeyForURL:imageURL] withType:YYImageCacheTypeMemory];
  116. }
  117. if (imageFromMemory) {
  118. if (!(options & YYWebImageOptionAvoidSetImage)) {
  119. self.image = imageFromMemory;
  120. }
  121. if(completion) completion(imageFromMemory, imageURL, YYWebImageFromMemoryCacheFast, YYWebImageStageFinished, nil);
  122. return;
  123. }
  124. if (!(options & YYWebImageOptionIgnorePlaceHolder)) {
  125. self.image = placeholder;
  126. }
  127. __weak typeof(self) _self = self;
  128. dispatch_async([_YYWebImageSetter setterQueue], ^{
  129. YYWebImageProgressBlock _progress = nil;
  130. if (progress) _progress = ^(NSInteger receivedSize, NSInteger expectedSize) {
  131. dispatch_async(dispatch_get_main_queue(), ^{
  132. progress(receivedSize, expectedSize);
  133. });
  134. };
  135. __block int32_t newSentinel = 0;
  136. __block __weak typeof(setter) weakSetter = nil;
  137. YYWebImageCompletionBlock _completion = ^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
  138. __strong typeof(_self) self = _self;
  139. BOOL setImage = (stage == YYWebImageStageFinished || stage == YYWebImageStageProgress) && image && !(options & YYWebImageOptionAvoidSetImage);
  140. dispatch_async(dispatch_get_main_queue(), ^{
  141. BOOL sentinelChanged = weakSetter && weakSetter.sentinel != newSentinel;
  142. if (setImage && self && !sentinelChanged) {
  143. BOOL showFade = ((options & YYWebImageOptionSetImageWithFadeAnimation) && !self.highlighted);
  144. if (showFade) {
  145. CATransition *transition = [CATransition animation];
  146. transition.duration = stage == YYWebImageStageFinished ? _YYWebImageFadeTime : _YYWebImageProgressiveFadeTime;
  147. transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  148. transition.type = kCATransitionFade;
  149. [self.layer addAnimation:transition forKey:_YYWebImageFadeAnimationKey];
  150. }
  151. self.image = image;
  152. }
  153. if (completion) {
  154. if (sentinelChanged) {
  155. completion(nil, url, YYWebImageFromNone, YYWebImageStageCancelled, nil);
  156. } else {
  157. completion(image, url, from, stage, error);
  158. }
  159. }
  160. });
  161. };
  162. newSentinel = [setter setOperationWithSentinel:sentinel url:imageURL options:options manager:manager progress:_progress transform:transform completion:_completion];
  163. weakSetter = setter;
  164. });
  165. });
  166. }
  167. - (void)cancelCurrentImageRequest {
  168. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageSetterKey);
  169. if (setter) [setter cancel];
  170. }
  171. #pragma mark - highlighted image
  172. - (NSURL *)highlightedImageURL {
  173. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageHighlightedSetterKey);
  174. return setter.imageURL;
  175. }
  176. - (void)setHighlightedImageURL:(NSURL *)imageURL {
  177. [self setHighlightedImageWithURL:imageURL
  178. placeholder:nil
  179. options:kNilOptions
  180. manager:nil
  181. progress:nil
  182. transform:nil
  183. completion:nil];
  184. }
  185. - (void)setHighlightedImageWithURL:(NSURL *)imageURL placeholder:(UIImage *)placeholder {
  186. [self setHighlightedImageWithURL:imageURL
  187. placeholder:placeholder
  188. options:kNilOptions
  189. manager:nil
  190. progress:nil
  191. transform:nil
  192. completion:nil];
  193. }
  194. - (void)setHighlightedImageWithURL:(NSURL *)imageURL options:(YYWebImageOptions)options {
  195. [self setHighlightedImageWithURL:imageURL
  196. placeholder:nil
  197. options:options
  198. manager:nil
  199. progress:nil
  200. transform:nil
  201. completion:nil];
  202. }
  203. - (void)setHighlightedImageWithURL:(NSURL *)imageURL
  204. placeholder:(UIImage *)placeholder
  205. options:(YYWebImageOptions)options
  206. completion:(YYWebImageCompletionBlock)completion {
  207. [self setHighlightedImageWithURL:imageURL
  208. placeholder:placeholder
  209. options:options
  210. manager:nil
  211. progress:nil
  212. transform:nil
  213. completion:completion];
  214. }
  215. - (void)setHighlightedImageWithURL:(NSURL *)imageURL
  216. placeholder:(UIImage *)placeholder
  217. options:(YYWebImageOptions)options
  218. progress:(YYWebImageProgressBlock)progress
  219. transform:(YYWebImageTransformBlock)transform
  220. completion:(YYWebImageCompletionBlock)completion {
  221. [self setHighlightedImageWithURL:imageURL
  222. placeholder:placeholder
  223. options:options
  224. manager:nil
  225. progress:progress
  226. transform:nil
  227. completion:completion];
  228. }
  229. - (void)setHighlightedImageWithURL:(NSURL *)imageURL
  230. placeholder:(UIImage *)placeholder
  231. options:(YYWebImageOptions)options
  232. manager:(YYWebImageManager *)manager
  233. progress:(YYWebImageProgressBlock)progress
  234. transform:(YYWebImageTransformBlock)transform
  235. completion:(YYWebImageCompletionBlock)completion {
  236. if ([imageURL isKindOfClass:[NSString class]]) imageURL = [NSURL URLWithString:(id)imageURL];
  237. manager = manager ? manager : [YYWebImageManager sharedManager];
  238. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageHighlightedSetterKey);
  239. if (!setter) {
  240. setter = [_YYWebImageSetter new];
  241. objc_setAssociatedObject(self, &_YYWebImageHighlightedSetterKey, setter, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  242. }
  243. int32_t sentinel = [setter cancelWithNewURL:imageURL];
  244. dispatch_async_on_main_queue(^{
  245. if ((options & YYWebImageOptionSetImageWithFadeAnimation) &&
  246. !(options & YYWebImageOptionAvoidSetImage)) {
  247. if (self.highlighted) {
  248. [self.layer removeAnimationForKey:_YYWebImageFadeAnimationKey];
  249. }
  250. }
  251. if (!imageURL) {
  252. if (!(options & YYWebImageOptionIgnorePlaceHolder)) {
  253. self.highlightedImage = placeholder;
  254. }
  255. return;
  256. }
  257. // get the image from memory as quickly as possible
  258. UIImage *imageFromMemory = nil;
  259. if (manager.cache &&
  260. !(options & YYWebImageOptionUseNSURLCache) &&
  261. !(options & YYWebImageOptionRefreshImageCache)) {
  262. imageFromMemory = [manager.cache getImageForKey:[manager cacheKeyForURL:imageURL] withType:YYImageCacheTypeMemory];
  263. }
  264. if (imageFromMemory) {
  265. if (!(options & YYWebImageOptionAvoidSetImage)) {
  266. self.highlightedImage = imageFromMemory;
  267. }
  268. if(completion) completion(imageFromMemory, imageURL, YYWebImageFromMemoryCacheFast, YYWebImageStageFinished, nil);
  269. return;
  270. }
  271. if (!(options & YYWebImageOptionIgnorePlaceHolder)) {
  272. self.highlightedImage = placeholder;
  273. }
  274. __weak typeof(self) _self = self;
  275. dispatch_async([_YYWebImageSetter setterQueue], ^{
  276. YYWebImageProgressBlock _progress = nil;
  277. if (progress) _progress = ^(NSInteger receivedSize, NSInteger expectedSize) {
  278. dispatch_async(dispatch_get_main_queue(), ^{
  279. progress(receivedSize, expectedSize);
  280. });
  281. };
  282. __block int32_t newSentinel = 0;
  283. __block __weak typeof(setter) weakSetter = nil;
  284. YYWebImageCompletionBlock _completion = ^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
  285. __strong typeof(_self) self = _self;
  286. BOOL setImage = (stage == YYWebImageStageFinished || stage == YYWebImageStageProgress) && image && !(options & YYWebImageOptionAvoidSetImage);
  287. BOOL showFade = ((options & YYWebImageOptionSetImageWithFadeAnimation) && self.highlighted);
  288. dispatch_async(dispatch_get_main_queue(), ^{
  289. BOOL sentinelChanged = weakSetter && weakSetter.sentinel != newSentinel;
  290. if (setImage && self && !sentinelChanged) {
  291. if (showFade) {
  292. CATransition *transition = [CATransition animation];
  293. transition.duration = stage == YYWebImageStageFinished ? _YYWebImageFadeTime : _YYWebImageProgressiveFadeTime;
  294. transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  295. transition.type = kCATransitionFade;
  296. [self.layer addAnimation:transition forKey:_YYWebImageFadeAnimationKey];
  297. }
  298. self.highlightedImage = image;
  299. }
  300. if (completion) {
  301. if (sentinelChanged) {
  302. completion(nil, url, YYWebImageFromNone, YYWebImageStageCancelled, nil);
  303. } else {
  304. completion(image, url, from, stage, error);
  305. }
  306. }
  307. });
  308. };
  309. newSentinel = [setter setOperationWithSentinel:sentinel url:imageURL options:options manager:manager progress:_progress transform:transform completion:_completion];
  310. weakSetter = setter;
  311. });
  312. });
  313. }
  314. - (void)cancelCurrentHighlightedImageRequest {
  315. _YYWebImageSetter *setter = objc_getAssociatedObject(self, &_YYWebImageHighlightedSetterKey);
  316. if (setter) [setter cancel];
  317. }
  318. @end