/* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIView+WebCache.h" #if SD_UIKIT || SD_MAC #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" static char imageURLKey; #if SD_UIKIT static char TAG_ACTIVITY_INDICATOR; static char TAG_ACTIVITY_STYLE; #endif static char TAG_ACTIVITY_SHOW; @implementation UIView (WebCache) - (nullable NSURL *)sd_imageURL { return objc_getAssociatedObject(self, &imageURLKey); } - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); [self sd_cancelImageLoadOperationWithKey:validOperationKey]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{ [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; }); } if (url) { // check if activityView is enabled or not if ([self sd_showActivityIndicatorView]) { [self sd_addActivityIndicator]; } __weak __typeof(self)wself = self; id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; [sself sd_removeActivityIndicator]; if (!sself) { return; } dispatch_main_async_safe(^{ if (!sself) { return; } if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { completedBlock(image, error, cacheType, url); return; } else if (image) { [sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } else { if ((options & SDWebImageDelayPlaceholder)) { [sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } } if (completedBlock && finished) { completedBlock(image, error, cacheType, url); } }); }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { dispatch_main_async_safe(^{ [self sd_removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); } }); } } - (void)sd_cancelCurrentImageLoad { [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; } - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock { if (setImageBlock) { setImageBlock(image, imageData); return; } #if SD_UIKIT || SD_MAC if ([self isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)self; imageView.image = image; } #endif #if SD_UIKIT if ([self isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)self; [button setImage:image forState:UIControlStateNormal]; } #endif } - (void)sd_setNeedsLayout { #if SD_UIKIT [self setNeedsLayout]; #elif SD_MAC [self setNeedsLayout:YES]; #endif } #pragma mark - Activity indicator #pragma mark - #if SD_UIKIT - (UIActivityIndicatorView *)activityIndicator { return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR); } - (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator { objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN); } #endif - (void)sd_setShowActivityIndicatorView:(BOOL)show { objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN); } - (BOOL)sd_showActivityIndicatorView { return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; } #if SD_UIKIT - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style{ objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN); } - (int)sd_getIndicatorStyle{ return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue]; } #endif - (void)sd_addActivityIndicator { #if SD_UIKIT dispatch_main_async_safe(^{ if (!self.activityIndicator) { self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self sd_getIndicatorStyle]]; self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:self.activityIndicator]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; } [self.activityIndicator startAnimating]; }); #endif } - (void)sd_removeActivityIndicator { #if SD_UIKIT dispatch_main_async_safe(^{ if (self.activityIndicator) { [self.activityIndicator removeFromSuperview]; self.activityIndicator = nil; } }); #endif } @end #endif