菜鸟简单解读AFNetworking

对于客户端开发来说,同网络请求相关的代码总是相对复杂的,因为它牵扯到request的序列化,response的解析,繁多的异常错误处理和多线程的调度……
很多iOS的开发人员,或许不知道NSURLConnection(现在官方已经不鼓励使用)、NSURLSession、NSURLSessionTask……但肯定知道AFNetworking(OC)与Alamofire(Swift)。在iOS端几乎所有与网络请求相关的处理,都会牵扯到这两个开源库。公司的网络层,会根据实际的业务的需要,在AFNetworking/Alamofire的基础上继续封装。
这里说一点儿题外话,之前我还不是特别理解为何要做过度封装,最近有所感受,主要原因有两点:

  1. 同一套底层设计,由于不同的业务需求会表现出明显的差异,因此需要在第三库的基础上,进一步封装成方便业务层代码调用的API。
  2. 无法保证第三库会有持续的维护,它可能会出现性能问题、bug或者版本的更迭。若自己封装过一层,那么在这些情况出现的时候,只需要对中间层进行维护,让业务层无感知。

先来想一想如果我们自己要写一个网络请求的库,它需要具备哪些功能:

  1. request的序列化:URL的拼接,参数解析并拼接成query,根据网络请求的方法(get、post、head……)生成正确的request
  2. 监听网络状况:当前的网络环境(WiFi还是cellular),网络安全状况(证书问题)
  3. 监听网络请求中的各个环节。例如:请求是否完成,客户端是否收到数据,是否发生错误等
  4. 针对与网络请求中的各个环节,要有相应的默认处理,最重要的是对各种异常错误的处理,保证到最后用户拿到的是想要的数据
  5. 对response的解析,各种格式JSON、XML等

针对第3点,看一看在AFNetworking是怎么实现。
这里不对代码中的一些细节作解释,若想一行一行地深究细节,推荐涂耀辉 - 简书大神写的AF解读系列。

AFNetworking是围绕着NSURLSession做了一层封装,先来看看NSURLSession的作用:

With the NSURLSession API, your app creates one or more sessions, each of which coordinates a group of related data transfer tasks. For example, if you are writing a web browser, your app might create one session per tab or window, or one session for interactive use and another session for background downloads. Within each session, your app adds a series of tasks, each of which represents a request for a specific URL (following HTTP redirects if necessary).
NSURLSession

同我们在做web开发时的session联系了起来,它是用来管理一系列的NSURLSessionTask,而我们的每一个request都会经由NSURLSession生成一个NSURLSessionTask。这样就明白了,NSURLSession就是用来管理一系列request的,至于如何管理,就不用管啦。事实上,苹果发布的NSURLSession的概念应该是从AF2.x借鉴过来的。当年的AF2.x是围绕着NSURLConnection做封装,结合NSOperation实现了网络请求的资源分配和线程调度。而如今,这一切都被内置的NSURLSession给实现了。而一个NSURLSession需要一个delegate,并实现一系列的NSURLSessionDelegate方法,这些方法就是在请求的各个环节被系统回调的,也就对应着第4个功能点。

在AF中,最核心的类是AFURLSessionManager,几乎所有同网络请求相关的核心操作都是由这个类完成或是调度完成的。我们常用的AFHTTPSessionManager是这个类的子类,子类只是封装了一下父类中的方法,其实并没有干实事。而在这个类中,就维护了一个NSURLSession类型的session。
先看看使用AF如何发出一个网络请求:

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"example.com"] sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

首先需要初始化一个AFURLSessionManager,也就在这个时候,内部的初始化函数创建了一个NSURLSession,而这个session的delegate也就是维护它的manager:

self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

随后,我们通过这个manager发出一个网络请求:

[manager GET:@"schema" parameters:nil progress:nil success:nil failure:nil];

在这段代码的背后,manager会通过传进来的URL和parameters序列化一个request,更进一步,manager中维护的session会为每一个request生成一个dataTask:

dataTask = [self.session dataTaskWithRequest:request];

最后只需要[dataTask resume]就可以触发这次网络请求任务了。
那么最关键的问题就变成了manager如何管理这些dataTask了。
我个人觉得,这就是AF中最关键的地方了:manager会为每一个dataTask配置一个AFURLSessionManagerTaskDelegate。
AFURLSessionManagerTaskDelegate中只不过是将NSURLSessionDelegate中的三个方法提取了出来,提供了完整的实现,这三个方法的签名是:

- URLSession:task:didCompleteWithError:
- URLSession:dataTask:didReceiveData:
- (void)URLSession:downloadTask:didFinishDownloadingToURL:

AFURLSessionManager本可以实现NSURLSessionDelegate的全部接口,那么为什么偏偏要把这三个方法提取出来,提供另外一个代理接口?主要原因可能是这样的:每一个dataTask都是很不一样的,若对一个session管理的所有dataTask都设置成同一个delegate(即manager),那么用户如何取到不同dataTask回调回来的不同信息?因此,我们需要把那些会针对不同dataTask返回不同数据信息的回调函数单独抽出来(因为不同dataTask返回的数据信息是不一样的),为每一个dataTask都配置一个delegate,而对于一些公共环节的处理则交给manager做统一处理。
感觉干看上面这段话,挺难懂的,贴图说明:

image.png

到这里为止,manager已经实现了对每一个dataTask的监听功能。当然我的解释很简短,AF中的细节实现还有大大的可以深究的地方(大神写的代码确实牛逼),但是细节方面需要粘贴大段的代码,笔者不是提别喜欢这种方式,强烈推荐涂耀辉 - 简书大神的《AFNetworking到底做了什么》系列。

本文章后续会有增修。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容