UIView+WebCache.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * This file is part of the SDWebImage package.
  3. * (c) Olivier Poitrey <rs@dailymotion.com>
  4. *
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. #import "UIView+WebCache.h"
  9. #if SD_UIKIT || SD_MAC
  10. #import "objc/runtime.h"
  11. #import "UIView+WebCacheOperation.h"
  12. static char imageURLKey;
  13. #if SD_UIKIT
  14. static char TAG_ACTIVITY_INDICATOR;
  15. static char TAG_ACTIVITY_STYLE;
  16. #endif
  17. static char TAG_ACTIVITY_SHOW;
  18. @implementation UIView (WebCache)
  19. - (nullable NSURL *)sd_imageURL {
  20. return objc_getAssociatedObject(self, &imageURLKey);
  21. }
  22. - (void)sd_internalSetImageWithURL:(nullable NSURL *)url
  23. placeholderImage:(nullable UIImage *)placeholder
  24. options:(SDWebImageOptions)options
  25. operationKey:(nullable NSString *)operationKey
  26. setImageBlock:(nullable SDSetImageBlock)setImageBlock
  27. progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
  28. completed:(nullable SDExternalCompletionBlock)completedBlock {
  29. NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
  30. [self sd_cancelImageLoadOperationWithKey:validOperationKey];
  31. objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  32. if (!(options & SDWebImageDelayPlaceholder)) {
  33. dispatch_main_async_safe(^{
  34. [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
  35. });
  36. }
  37. if (url) {
  38. // check if activityView is enabled or not
  39. if ([self sd_showActivityIndicatorView]) {
  40. [self sd_addActivityIndicator];
  41. }
  42. __weak __typeof(self)wself = self;
  43. id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
  44. __strong __typeof (wself) sself = wself;
  45. [sself sd_removeActivityIndicator];
  46. if (!sself) {
  47. return;
  48. }
  49. dispatch_main_async_safe(^{
  50. if (!sself) {
  51. return;
  52. }
  53. if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
  54. completedBlock(image, error, cacheType, url);
  55. return;
  56. } else if (image) {
  57. [sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock];
  58. [sself sd_setNeedsLayout];
  59. } else {
  60. if ((options & SDWebImageDelayPlaceholder)) {
  61. [sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
  62. [sself sd_setNeedsLayout];
  63. }
  64. }
  65. if (completedBlock && finished) {
  66. completedBlock(image, error, cacheType, url);
  67. }
  68. });
  69. }];
  70. [self sd_setImageLoadOperation:operation forKey:validOperationKey];
  71. } else {
  72. dispatch_main_async_safe(^{
  73. [self sd_removeActivityIndicator];
  74. if (completedBlock) {
  75. NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
  76. completedBlock(nil, error, SDImageCacheTypeNone, url);
  77. }
  78. });
  79. }
  80. }
  81. - (void)sd_cancelCurrentImageLoad {
  82. [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])];
  83. }
  84. - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock {
  85. if (setImageBlock) {
  86. setImageBlock(image, imageData);
  87. return;
  88. }
  89. #if SD_UIKIT || SD_MAC
  90. if ([self isKindOfClass:[UIImageView class]]) {
  91. UIImageView *imageView = (UIImageView *)self;
  92. imageView.image = image;
  93. }
  94. #endif
  95. #if SD_UIKIT
  96. if ([self isKindOfClass:[UIButton class]]) {
  97. UIButton *button = (UIButton *)self;
  98. [button setImage:image forState:UIControlStateNormal];
  99. }
  100. #endif
  101. }
  102. - (void)sd_setNeedsLayout {
  103. #if SD_UIKIT
  104. [self setNeedsLayout];
  105. #elif SD_MAC
  106. [self setNeedsLayout:YES];
  107. #endif
  108. }
  109. #pragma mark - Activity indicator
  110. #pragma mark -
  111. #if SD_UIKIT
  112. - (UIActivityIndicatorView *)activityIndicator {
  113. return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR);
  114. }
  115. - (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator {
  116. objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN);
  117. }
  118. #endif
  119. - (void)sd_setShowActivityIndicatorView:(BOOL)show {
  120. objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN);
  121. }
  122. - (BOOL)sd_showActivityIndicatorView {
  123. return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue];
  124. }
  125. #if SD_UIKIT
  126. - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style{
  127. objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN);
  128. }
  129. - (int)sd_getIndicatorStyle{
  130. return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue];
  131. }
  132. #endif
  133. - (void)sd_addActivityIndicator {
  134. #if SD_UIKIT
  135. dispatch_main_async_safe(^{
  136. if (!self.activityIndicator) {
  137. self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self sd_getIndicatorStyle]];
  138. self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
  139. [self addSubview:self.activityIndicator];
  140. [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
  141. attribute:NSLayoutAttributeCenterX
  142. relatedBy:NSLayoutRelationEqual
  143. toItem:self
  144. attribute:NSLayoutAttributeCenterX
  145. multiplier:1.0
  146. constant:0.0]];
  147. [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
  148. attribute:NSLayoutAttributeCenterY
  149. relatedBy:NSLayoutRelationEqual
  150. toItem:self
  151. attribute:NSLayoutAttributeCenterY
  152. multiplier:1.0
  153. constant:0.0]];
  154. }
  155. [self.activityIndicator startAnimating];
  156. });
  157. #endif
  158. }
  159. - (void)sd_removeActivityIndicator {
  160. #if SD_UIKIT
  161. dispatch_main_async_safe(^{
  162. if (self.activityIndicator) {
  163. [self.activityIndicator removeFromSuperview];
  164. self.activityIndicator = nil;
  165. }
  166. });
  167. #endif
  168. }
  169. @end
  170. #endif