源码阅读:AFNetworking(十六)——UIWebView+AFNetworking
该文章阅读的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
源码阅读:AFNetworking(十六)——UIWebView+AFNetworking相关推荐
- Soul网关源码阅读(十)自定义简单插件编写
Soul网关源码阅读(十)自定义简单插件编写 简介 综合前面所分析的插件处理流程相关知识,此次我们来编写自定义的插件:统计请求在插件链中的经历时长 编写准备 首先我们先探究一下,一个P ...
- Go-Excelize API源码阅读(十九)——SetHeaderFooter
Go-Excelize API源码阅读(十九)--SetHeaderFooter 开源摘星计划(WeOpen Star) 是由腾源会 2022 年推出的全新项目,旨在为开源人提供成长激励,为开源项目提 ...
- php网页游戏学习之xnova(ogame)源码解读,PHP网页游戏学习之Xnova(ogame)源码解读(十六)...
PHP网页游戏学习之Xnova(ogame)源码解读(十六) 作者:bea 十九.攻击任务(MissionCaseAttack.php) 按照舰队任务的编号,排在第一个的就是攻击任务.这个代码很长,看 ...
- Spark修炼之道(高级篇)——Spark源码阅读:第六节 Task提交
Task提交 在上一节中的 Stage提交中我们提到,最终stage被封装成TaskSet,使用taskScheduler.submitTasks提交,具体代码如下: taskScheduler.su ...
- 【转】ABP源码分析四十六:ABP ZERO中的Ldap模块
通过AD作为用户认证的数据源.整个管理用户认证逻辑就在LdapAuthenticationSource类中实现. LdapSettingProvider:定义LDAP的setting和提供Defaut ...
- 【转】ABP源码分析三十六:ABP.Web.Api
这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...
- 【转】ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- ABP源码分析三十六:ABP.Web.Api
这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...
- 第二人生的源码分析(二十六)底层网络协议
为了理解第二人生的客户端与服务器的沟通,那么下面就来分析一下第二人生采用的网络协议.在目前的网络里,主要有两个协议:TCP和UDP,而第二人生里是采用UDP协议.TCP协议与UDP协议的主要区别,就是 ...
- skywalking源码分析第十六篇一agent端JVMService之度量上报
文章目录 原理图 原理图一基于MXBean进行Metrics数据收集 源码分析一JVMService 总结 原理图 通过prepare构建Metrics存储缓冲队列 初始化grpc客户端 通过boot ...
最新文章
- Linux中ifreq 结构体分析和使用
- VScode Python插件
- 主页面功能的java_6-04-项目实战-主页面显示当前用户退出功能实现
- java堆和客栈_JAVA中堆、栈,静态方法和非静态方法的速度问题
- ROS Nodelet使用
- fisco bcos应用开发(一) springboot报错 Error reading resource
- 不学点《近世代数》怎么学好现代密码学
- Multisim卸载后重新安装不上解决方案
- ApacheCN 活动汇总 2019.8.23
- 一键下载QQ空间相册
- SaaS已死。下一个。
- linux恢复误删除文件
- 按钮样式动态切换js
- 使用ETE包让系统发育树(进化树)和多重序列比对(MSA)“同框”
- luffy-(12)
- 5G/NR 随机接入过程之PRACH时域资源
- 第 16 章 string类和标准模板库
- Google全系列产品不再信任赛门铁克某款根证书
- php仿u8系统模板_中文分词源码_7urpu8 采用php的源码实现 - 下载 - 搜珍网
- vue IE下验证码无法显示解决方法
热门文章
- C++实现tar包解析
- 【Qt】Qt源码中涉及到的设计模式
- 【Qt】调用Python函数:无参数、单个参数、多个参数、数组参数
- 【imx6】Unable to find the ncurses libraries的解决办法
- webkit内核 css,纯CSS改变webkit内核浏览器的滚动条样式
- uniapp 鸿蒙,关于前端:uniapp项目安装运行操作手册
- alexnet训练多久收敛_如何将深度学习训练速度提升一百倍?PAISoar 来了
- 正向最大匹配算法 python代码_中文分词算法之最大正向匹配算法(Python版)
- Mybatis入门:4(多表查询操作)
- Java学习总结:24