源码分析之AFNetworking④UIkit+AFNetworking
Posted 梦想家-mxj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码分析之AFNetworking④UIkit+AFNetworking相关的知识,希望对你有一定的参考价值。
如果需要使用AFNetworking的UIKit扩展时可直接在prefix.pch文件中引入,或者在工程的相关文件中引入。
1、AFAutoPurgingImageCache :用于缓存图片的类,通过identifier来添加和搜索UIImage
协议中添加图片:
- (void)addImage:(UIImage*)image withIdentifier:(NSString *)identifier;
协议中删除图片
- (BOOL)removeImageWithIdentifier:(NSString*)identifier;
通过identifier获取图片的方法:
- (nullable UIImage*)imageWithIdentifer:(NSString *)identifier;
2、UIButton+AFNetworking
UIButton跟图片相关的属性大概有两个,Image和BackgroundImage,所以这个分类就是赋予他们异步加载图片的能力。
核心的方法如下:
①
- (void)setImageForState:(UIControlState)state
withURL:(NSURL *)url;
异步下载指定url的图片,并且一旦请求完成就将其设置为某种状态的图片。如果图片已经被缓存在本地了,那么就取本地的图片、或者显示指定的占位图,等远程图片下载完成就立即替换。
②
- (void)setImageForState:(UIControlState)state
withURL:(NSURL *)url
placeholderImage:(nullable UIImage *)placeholderImage;
和①一样都是异步下载指定url的图片
③
- (void)setImageForState:(UIControlState)state
withURLRequest:(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)setBackgroundImageForState:(UIControlState)state
withURL:(NSURL *)url;
异步下载指定url的图片,并将图片设置为某种状态的按钮的背景图片
⑤
- (void)setBackgroundImageForState:(UIControlState)state
withURL:(NSURL *)url
placeholderImage:(nullable UIImage *)placeholderImage;
比④多了占位的背景图
⑥
- (void)setBackgroundImageForState:(UIControlState)state
withURLRequest:(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)cancelImageDownloadTaskForState:(UIControlState)state;
⑧
- (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state;
取消下载操作
3、UIImageView+AFNetworking
UIImageView+AFNetworking 是AFNetworking中一个实现图片异步加载的类,它是为系统中的UIImageView类添加的分类,这个分类中的方法未远程异步加载图片的功能提供支持。
- (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;
上面三个方法都是UIImageView异步下载指定url的图片。首先会检查本地有没有缓存图片,如果有就返回,没有就去下载;如果有占位图,就显示展位图,然后下载远程图片,替换展位图。
上面的三个方法最终会调用
AFImageDownloader的对象方法:
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
withReceiptID:(nonnull NSUUID *)receiptID
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
在这个方法内部会将下载的图片缓存起来。
4、WKWebView+AFNetworking
WKWebView+AFNetworking这个是WKwebview的扩展类,里面有两个方法
①
- (void)loadRequest:(NSURLRequest *)request
navigation:(WKNavigation * _Nonnull)navigation
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSString * (^)(NSHTTPURLResponse *response, NSString *html))success
failure:(nullable void (^)(NSError *error))failure;
异步加载请求
request 一个标识加载内容位置的url 请求,不可为nil
navigation Wk的导航,不可为nil
progress 加载进度
success 成功回调
failure 失败回调
②
- (void)loadRequest:(NSURLRequest *)request
navigation:(WKNavigation * _Nonnull)navigation
MIMEType:(nullable NSString *)MIMEType
textEncodingName:(nullable NSString *)textEncodingName
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(nullable void (^)(NSError *error))failure;
查看方法内部实现,①最终会调用②的方法
5、UIProgressView+AFNetworking
为UIProgressView控件绑定task方法,从而获取task的上传下载进度。
调用的API
为指定的上传任务绑定进度控件
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated;
为指定的下载任务绑定进度控件
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated;
查看里面的源码可以看到:
- (BOOL)af_uploadProgressAnimated
return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_uploadProgressAnimated)) boolValue];
- (void)af_setUploadProgressAnimated:(BOOL)animated
objc_setAssociatedObject(self, @selector(af_uploadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (BOOL)af_downloadProgressAnimated
return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_downloadProgressAnimated)) boolValue];
- (void)af_setDownloadProgressAnimated:(BOOL)animated
objc_setAssociatedObject(self, @selector(af_downloadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
这四个方法,通过runtime管理的对象为分类添加属性保存进度条的动画选项。
在上传绑定的实现里
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated
if (task.state == NSURLSessionTaskStateCompleted)
return;
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
[task addObserver:self forKeyPath:@"countOfBytesSent" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
[self af_setUploadProgressAnimated:animated];
通过KVO观察task的state和countOfBytesSent属性
下载绑定的实现里
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated
if (task.state == NSURLSessionTaskStateCompleted)
return;
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];
[task addObserver:self forKeyPath:@"countOfBytesReceived" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];
[self af_setDownloadProgressAnimated:animated];
通过KVO观察task的state和countOfBytesReceived属性
里面有两个静态常量
//任务发送字节数量上下文
static void * AFTaskCountOfBytesSentContext = &AFTaskCountOfBytesSentContext;
//任务接受字节数量上下文
static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedContext;
在KVO的回调中
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(__unused NSDictionary *)change
context:(void *)context
//如果是通过分类添加的观察者(AFTaskCountOfBytesSentContext、AFTaskCountOfBytesReceivedContext)
if (context == AFTaskCountOfBytesSentContext || context == AFTaskCountOfBytesReceivedContext)
//如果task的countOfBytesSent属性发生变化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))])
if ([object countOfBytesExpectedToSend] > 0)
dispatch_async(dispatch_get_main_queue(), ^//主线程异步调用
//计算当前的发送进度并未progressview赋值
[self setProgress:[object countOfBytesSent] / ([object countOfBytesExpectedToSend] * 1.0f) animated:self.af_uploadProgressAnimated];
);
//如果task的countOfBytesReceived属性发生变化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))])
if ([object countOfBytesExpectedToReceive] > 0) //接受的总大小
dispatch_async(dispatch_get_main_queue(), ^
//计算当前进度并未控件赋值
[self setProgress:[object countOfBytesReceived] / ([object countOfBytesExpectedToReceive] * 1.0f) animated:self.af_downloadProgressAnimated];
);
//如果是通过task的state属性发生变化
if ([keyPath isEqualToString:NSStringFromSelector(@selector(state))])
if ([(NSURLSessionTask *)object state] == NSURLSessionTaskStateCompleted)
//完成时,就移除对task的state、 countOfBytesSent、countOfBytesReceived属性的观察
@try
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(state))];
if (context == AFTaskCountOfBytesSentContext)
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
if (context == AFTaskCountOfBytesReceivedContext)
[object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];
@catch (NSException * __unused exception)
总的来说,绑定进度条控件主要是通过kvo观察task的属性变化实现的,并在kvo的回到中更新控件进度,在完成后移除对task相关属性的监听。
以上是关于源码分析之AFNetworking④UIkit+AFNetworking的主要内容,如果未能解决你的问题,请参考以下文章
源码分析之AFNetworking④UIkit+AFNetworking
源码分析之AFNetworking④UIkit+AFNetworking
源码分析之AFNetworking ②AFNetworkReachabilityManager
源码分析之AFNetworking ②AFNetworkReachabilityManager
源码分析之AFNetworking ②AFNetworkReachabilityManager
源码分析之AFNetworking③AFSecurityPolicy和AFURLRequestSerialization