UIImageView+AFNetworking源码学习

建立了一个UIImageVIew的类别,提供异步下载远程图片的方法:

@interface UIImageView (AFNetworking)
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader;
+ (AFImageDownloader *)sharedImageDownloader;

- (void)setImageWithURL:(NSURL *)url;
- (void)setImageWithURL:(NSURL *)url
       placeholderImage:(nullable UIImage *)placeholderImage;
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
              placeholderImage:(nullable UIImage *)placeholderImage
                       success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                       failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
- (void)cancelImageDownloadTask;

@end

关于AFImageDownloader,请参考这篇文章。

在UIImageView+AFNetworking.m中为UIImageVIew添加类别并定义属性:af_activeImageDownloadReceipt。AFImageDownloadReceipt类用来监听下载进度和取消下载。

@interface UIImageView (_AFNetworking)
@property (readwrite, nonatomic, strong, setter = af_setActiveImageDownloadReceipt:) AFImageDownloadReceipt *af_activeImageDownloadReceipt;
@end

@implementation UIImageView (_AFNetworking)

- (AFImageDownloadReceipt *)af_activeImageDownloadReceipt {
    return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, @selector(af_activeImageDownloadReceipt));
}

- (void)af_setActiveImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt {
    objc_setAssociatedObject(self, @selector(af_activeImageDownloadReceipt), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

UIImageView+AFNetworking的实现@implementation UIImageView (AFNetworking):
设置和获取图片下载器,默认的图片下载器为AFImageDownloader。

+ (AFImageDownloader *)sharedImageDownloader {
    return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
}

+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
    objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

图片下载:

- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
              placeholderImage:(UIImage *)placeholderImage
                       success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                       failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{
    //如果url不存在,取消当前下载任务,将receipt设为nil,把placeholderImage设置为当前显示的图片。
    if ([urlRequest URL] == nil) {
        [self cancelImageDownloadTask];
        self.image = placeholderImage;
        return;
    }
    //如果该url正在下载中,则忽略这次请求。所以如果想重新下载的话,要先cancelImageDownloadTask
    if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
        return;
    }
    //如果url存在并且没有正在下载该url,这取消正在下载的url。
    [self cancelImageDownloadTask];

    AFImageDownloader *downloader = [[self class] sharedImageDownloader];
    id  imageCache = downloader.imageCache;

    //查看缓存中是否有该url的图片。
    UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
    if (cachedImage) {
        //如果有,这里分两种情况
        //提供了success回调,则把图片传入回调中
        //没有提供success回调,则把图片直接赋予self.image
        if (success) {
            success(urlRequest, nil, cachedImage);
        } else {
            self.image = cachedImage;
        }
        [self clearActiveDownloadInformation];
    } else {
        if (placeholderImage) {
            self.image = placeholderImage;
        }
        //开始下载图片,并将downloader返回的receipt保存为self.af_activeImageDownloadReceipt
        //之所以在外部提供downloadID,是让闭包捕获这个值,并且这个值也是receipt的receiptID,因此在请求的返回闭包中,可以判断这个返回是否是最新下载的返回,如若不是,则不处理。
        __weak __typeof(self)weakSelf = self;
        NSUUID *downloadID = [NSUUID UUID];
        AFImageDownloadReceipt *receipt;
        receipt = [downloader
                   downloadImageForURLRequest:urlRequest
                   withReceiptID:downloadID
                   success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                       if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                          //与之前一样,如果提供了success则将UIImage返回给success回调。
                          //没有提供则直接给imageView.image赋值。
                           if (success) {
                               success(request, response, responseObject);
                           } else if(responseObject) {
                               strongSelf.image = responseObject;
                           }
                          //不要忘了把当前请求干掉
                           [strongSelf clearActiveDownloadInformation];
                       }

                   }
                   failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                        if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                            if (failure) {
                                failure(request, response, error);
                            }
                            //不要忘了把当前请求干掉
                            [strongSelf clearActiveDownloadInformation];
                        }
                   }];

        self.af_activeImageDownloadReceipt = receipt;
    }
}

其它:

//给ImageDownload使用Receipt来取消下载
- (void)cancelImageDownloadTask {
    if (self.af_activeImageDownloadReceipt != nil) {
        [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:self.af_activeImageDownloadReceipt];
        [self clearActiveDownloadInformation];
     }
}

//将receipt置为nil
- (void)clearActiveDownloadInformation {
    self.af_activeImageDownloadReceipt = nil;
}

//判断urlRequest是否是正在下载的请求
- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest {
    return [self.af_activeImageDownloadReceipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}

你可能感兴趣的:(UIImageView+AFNetworking源码学习)