该文章阅读的AFNetworking的版本为3.2.0。
这个分类提供了对请求周期进行控制的方法,包括进度监控、成功和失败的回调。
1.接口文件
1.1.属性
/**网络会话管理者对象*/
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
复制代码
1.2.方法
/**异步加载指定请求*/
- (void)loadRequest:(NSURLRequest *)requestprogress:(NSProgress * _Nullable __autoreleasing * _Nullable)progresssuccess:(nullable NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))successfailure:(nullable void (^)(NSError *error))failure;/**以指定MIME类型和指定文本编码格式异步加载指定请求*/
- (void)loadRequest:(NSURLRequest *)requestMIMEType:(nullable NSString *)MIMETypetextEncodingName:(nullable NSString *)textEncodingNameprogress:(NSProgress * _Nullable __autoreleasing * _Nullable)progresssuccess:(nullable NSData * (^)(NSHTTPURLResponse *response, NSData *data))successfailure:(nullable void (^)(NSError *error))failure;
复制代码
2.UIWebView+_AFNetworking私有分类
2.1.接口
/**保存任务对象*/
@property (readwrite, nonatomic, strong, setter = af_setURLSessionTask:) NSURLSessionDataTask *af_URLSessionTask;
复制代码
2.2.实现
这两个方法就是通过Runtime的关联对象为分类添加属性保存任务对象
- (NSURLSessionDataTask *)af_URLSessionTask {return (NSURLSessionDataTask *)objc_getAssociatedObject(self, @selector(af_URLSessionTask));
}- (void)af_setURLSessionTask:(NSURLSessionDataTask *)af_URLSessionTask {objc_setAssociatedObject(self, @selector(af_URLSessionTask), af_URLSessionTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
复制代码
3.方法实现
- 属性的访问方法
下面的这四个方法同样是通过关联对象为分类添加属,分别是保存网络会话管理者对象和响应序列化对象
- (AFHTTPSessionManager *)sessionManager {static AFHTTPSessionManager *_af_defaultHTTPSessionManager = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_af_defaultHTTPSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];_af_defaultHTTPSessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];_af_defaultHTTPSessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];});return objc_getAssociatedObject(self, @selector(sessionManager)) ?: _af_defaultHTTPSessionManager;
}- (void)setSessionManager:(AFHTTPSessionManager *)sessionManager {objc_setAssociatedObject(self, @selector(sessionManager), sessionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}- (AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {static AFHTTPResponseSerializer <AFURLResponseSerialization> *_af_defaultResponseSerializer = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_af_defaultResponseSerializer = [AFHTTPResponseSerializer serializer];});return objc_getAssociatedObject(self, @selector(responseSerializer)) ?: _af_defaultResponseSerializer;
}- (void)setResponseSerializer:(AFHTTPResponseSerializer<AFURLResponseSerialization> *)responseSerializer {objc_setAssociatedObject(self, @selector(responseSerializer), responseSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
复制代码
- 接口方法实现
- (void)loadRequest:(NSURLRequest *)requestprogress:(NSProgress * _Nullable __autoreleasing * _Nullable)progresssuccess:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))successfailure:(void (^)(NSError *error))failure
{// 调用下面的方法[self loadRequest:request MIMEType:nil textEncodingName:nil progress:progress success:^NSData *(NSHTTPURLResponse *response, NSData *data) {// 设置字符编码方式为UTF8NSStringEncoding stringEncoding = NSUTF8StringEncoding;// 如果响应对象有文本编码方式,就将字符编码方式设置为响应的文本编码方式if (response.textEncodingName) {CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);if (encoding != kCFStringEncodingInvalidId) {stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);}}// 将返回的数据进行编码NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding];// 如果设置了成功回调就调用block传递数据if (success) {string = success(response, string);}// 将字符串编码成二进制数据后返回return [string dataUsingEncoding:stringEncoding];} failure:failure];
}- (void)loadRequest:(NSURLRequest *)requestMIMEType:(NSString *)MIMETypetextEncodingName:(NSString *)textEncodingNameprogress:(NSProgress * _Nullable __autoreleasing * _Nullable)progresssuccess:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))successfailure:(void (^)(NSError *error))failure
{// 在debug模式下缺少参数就crashNSParameterAssert(request);// 如果当前已经有任务正在进行或者已经暂停,就取消掉这个任务,并将保存它的属性置空if (self.af_URLSessionTask.state == NSURLSessionTaskStateRunning || self.af_URLSessionTask.state == NSURLSessionTaskStateSuspended) {[self.af_URLSessionTask cancel];}self.af_URLSessionTask = nil;// 生成任务__weak __typeof(self)weakSelf = self;__block NSURLSessionDataTask *dataTask;dataTask = [self.sessionManagerdataTaskWithRequest:requestuploadProgress:nildownloadProgress:nilcompletionHandler:^(NSURLResponse * _Nonnull response, id _Nonnull responseObject, NSError * _Nullable error) {__strong __typeof(weakSelf) strongSelf = weakSelf;// 如果出错就调用失败回调blockif (error) {if (failure) {failure(error);}// 如果成功} else {// 先调用成功回调blockif (success) {success((NSHTTPURLResponse *)response, responseObject);}// 调用UIWebView加载本地数据的方式进行加载页面[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[dataTask.currentRequest URL]];// 调用UIWebView代理中的完成加载方法if ([strongSelf.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {[strongSelf.delegate webViewDidFinishLoad:strongSelf];}}}];// 用属性保存任务对象self.af_URLSessionTask = dataTask;// 如果设置了进度对象,就获取到网络会话管理者的下载进程对象if (progress != nil) {*progress = [self.sessionManager downloadProgressForTask:dataTask];}// 启动任务[self.af_URLSessionTask resume];// 调用UIWebView代理中的开始加载方法if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {[self.delegate webViewDidStartLoad:self];}复制代码
4.总结
看完这个分类的源码,我们可以看到这个分类做的事就是,手动实现了UIWebView
加载网络数据的过程,从而可以监听进度和通过block回调处理成功与失败的结果。
通常,我们会使用loadRequest:
方法加载指定页面,然后通过UIWebViewDelegate
中的方法监听网页加载的开始、结束与失败。
而这个分类,通过AFHTTPSessionManager
类手动生成NSURLSessionDataTask
对象下载网页的二进制数据,然后通过loadData: MIMEType: textEncodingName: baseURL:
方法加载已经下载到本地的网页的二进制数据。在这个过程中通过AFHTTPSessionManager
类中已经实现的方法实现进度的监控、成功和失败的回调。
源码阅读系列:AFNetworking
源码阅读:AFNetworking(一)——从使用入手
源码阅读:AFNetworking(二)——AFURLRequestSerialization
源码阅读:AFNetworking(三)——AFURLResponseSerialization
源码阅读:AFNetworking(四)——AFSecurityPolicy
源码阅读:AFNetworking(五)——AFNetworkReachabilityManager
源码阅读:AFNetworking(六)——AFURLSessionManager
源码阅读:AFNetworking(七)——AFHTTPSessionManager
源码阅读:AFNetworking(八)——AFAutoPurgingImageCache
源码阅读:AFNetworking(九)——AFImageDownloader
源码阅读:AFNetworking(十)——AFNetworkActivityIndicatorManager
源码阅读:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源码阅读:AFNetworking(十二)——UIButton+AFNetworking
源码阅读:AFNetworking(十三)——UIImageView+AFNetworking
源码阅读:AFNetworking(十四)——UIProgressView+AFNetworking
源码阅读:AFNetworking(十五)——UIRefreshControl+AFNetworking
源码阅读:AFNetworking(十六)——UIWebView+AFNetworking