建立了一个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];
}