該文章閱讀的AFNetworking的版本爲3.2.0。緩存
這個分類是爲UIImageView
添加異步加載網絡圖片的方法bash
/**
設置用於下載圖片的圖片下載器
*/
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader;
/**
獲取用於下載圖片的圖片下載器
*/
+ (AFImageDownloader *)sharedImageDownloader;
複製代碼
/**
爲圖片視圖設置指定圖片連接的圖片
*/
- (void)setImageWithURL:(NSURL *)url;
/**
爲圖片視圖設置指定圖片連接的圖片,以及指定佔位圖
*/
- (void)setImageWithURL:(NSURL *)url
placeholderImage:(nullable UIImage *)placeholderImage;
/**
爲圖片視圖設置指定圖片連接、指定佔位圖以及指定成功與失敗回調block的圖片
*/
- (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;
複製代碼
/**
用於保存下載封裝對象
*/
@property (readwrite, nonatomic, strong, setter = af_setActiveImageDownloadReceipt:) AFImageDownloadReceipt *af_activeImageDownloadReceipt;
複製代碼
實現裏的兩個方法就是經過Runtime的關聯對象爲分類添加屬性保存下載封裝對象網絡
- (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);
}
複製代碼
這兩個方法一樣是經過關聯對象爲分類添加屬性保存圖片下載對象異步
+ (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)setImageWithURL:(NSURL *)url {
// 調用下面的方法
[self setImageWithURL:url placeholderImage:nil];
}
- (void)setImageWithURL:(NSURL *)url
placeholderImage:(UIImage *)placeholderImage
{
// 經過圖片連接生成請求對象,而後調用下面的方法
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
[self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil];
}
- (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
{
// 若是請求對象的連接爲空,就取消掉以前的圖片下載任務,展現佔位圖,返回結束
if ([urlRequest URL] == nil) {
[self cancelImageDownloadTask];
self.image = placeholderImage;
return;
}
// 若是這個網絡請求正在進行中就不重複執行了
if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
return;
}
// 取消掉以前的圖片下載任務
[self cancelImageDownloadTask];
// 獲取圖片下載器對象
AFImageDownloader *downloader = [[self class] sharedImageDownloader];
// 獲取圖片下載器對象中的圖片緩存對象
id <AFImageRequestCache> imageCache = downloader.imageCache;
// 從圖片緩存對象中獲取緩存圖片
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
// 若是有緩存圖片
if (cachedImage) {
// 若是設置了成功回調block就調用block,不然就直接設置圖片
if (success) {
success(urlRequest, nil, cachedImage);
} else {
self.image = cachedImage;
}
[self clearActiveDownloadInformation];
// 若是沒有緩存圖片
} else {
// 若是設置了佔位圖就展現佔位圖
if (placeholderImage) {
self.image = placeholderImage;
}
// 獲取UUID,生成下載封裝對象,並開始下載
__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]) {
// 若是設置了成功回調block就調用block,不然就直接設置圖片
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]) {
// 若是設置了失敗回調block就調用block
if (failure) {
failure(request, response, error);
}
// 清除該控件的下載任務信息
[strongSelf clearActiveDownloadInformation];
}
}];
// 使用屬性保存生成的下載封裝對象
self.af_activeImageDownloadReceipt = receipt;
}
}
- (void)cancelImageDownloadTask {
// 若是當前有下載任務
if (self.af_activeImageDownloadReceipt != nil) {
// 經過任務封裝對象將下載任務取消
[[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:self.af_activeImageDownloadReceipt];
// 清除該控件的下載任務信息
[self clearActiveDownloadInformation];
}
}
- (void)clearActiveDownloadInformation {
// 將保存下載封裝對象的屬性置空
self.af_activeImageDownloadReceipt = nil;
}
- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest {
// 判斷屬性中保存的下載封裝對象的下載連接和傳入的請求對象下載連接是否相同
return [self.af_activeImageDownloadReceipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}
複製代碼
能夠看到爲UIImageView
設置圖片的邏輯和爲UIButton
設置圖片的邏輯基本相同,不太同樣的是設置UIButton
圖片的時候,還會根據設置的據控件的狀態進行區分和辨別。post
源碼閱讀系列:AFNetworkingui
源碼閱讀:AFNetworking(一)——從使用入手atom
源碼閱讀:AFNetworking(二)——AFURLRequestSerializationurl
源碼閱讀:AFNetworking(三)——AFURLResponseSerializationspa
源碼閱讀:AFNetworking(四)——AFSecurityPolicy3d
源碼閱讀:AFNetworking(五)——AFNetworkReachabilityManager
源碼閱讀:AFNetworking(六)——AFURLSessionManager
源碼閱讀:AFNetworking(七)——AFHTTPSessionManager
源碼閱讀:AFNetworking(八)——AFAutoPurgingImageCache
源碼閱讀:AFNetworking(九)——AFImageDownloader
源碼閱讀:AFNetworking(十)——AFNetworkActivityIndicatorManager
源碼閱讀:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源碼閱讀:AFNetworking(十二)——UIButton+AFNetworking
源碼閱讀:AFNetworking(十三)——UIImageView+AFNetworking
源碼閱讀:AFNetworking(十四)——UIProgressView+AFNetworking