版权地址:https://www.jianshu.com/p/5f8e56a17d85
作者:有毒的程序猿
说明:八点钟学院二期学员
学院链接:https://ke.qq.com/course/171725
前言
上海快30岁了月入3W, 为什么还是焦虑?
你焦虑, 是因为你月入三万的姿势不对! 如果你月入三万的组成是:月薪1万, 另外四套房子租金两万, 绝对不会焦虑.
![](https://i-blog.csdnimg.cn/blog_migrate/0e114a6a7c57d1a3eb7d4ae116d6f13d.webp?x-image-process=image/format,png)
介绍
- 这篇文章主要对
AFNetworking
的对外接口和请求处理文件进行阅读, 会拿出里面的优秀的技术点进行介绍.
一、AFHTTPSessionManager
AFHTTPSessionManager
类主要是对外提供接口, 通过调用父类方法封装一些常用接口.
AFHTTPSessionManager
继承自AFURLSessionManager
,并且实现了<NSSecureCoding, NSCopying>两个协议,如果对这两个协议想要深入了解可以点击这里;
A.NSCoder
- (instancetype)initWithCoder:(NSCoder *)decoder;
//解档 扩展 通过XIB创建的一个nib文件,会调用相关类的这个方法
- (void)encodeWithCoder:(NSCoder *)coder;//归档
+ (BOOL)supportsSecureCoding;支持NSSecureCoding
B.clang warning
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//code
#pragma clang diagnostic pop
表示在这个区间里忽略一些特定的clang的编译警告,因为AFNetworking作为一个库被其他项目引用,所以不能全局忽略clang的一些警告,只能在有需要的时候局部这样做,所以经常见忽略-Wgnu警告的写法,
详见这里
。
C.description
- (
NSString *)description {
return [
NSString stringWithFormat:
@"<%@: %p, baseURL: %@, session: %@, operationQueue: %@>",
NSStringFromClass([
self
class]),
self, [
self.baseURL absoluteString],
self.session,
self.operationQueue];
}
相信跟多人跟我一样经常忽略
description
,它是
NSObject
里面带的一个属性,并且携带了一个方法
- (NSString *)description
. 它就是我们打印对象时所显示的内容,默认状态下, 我们比如打印一个类:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSLog(@
"%@", manager);
// 不重写description
<
AFHTTPSessionManager:
0x6000001ccc60>
// 重写description之后输出的使我们自定制内容
<
AFHTTPSessionManager:
0x6000001ccc60,
baseURL: (null),
session: <
__NSURLSessionLocal:
0x7faa8f706420>,
operationQueue: <
NSOperationQueue:
0x60400003cc60>{name =
'NSOperationQueue 0x60400003cc60'}>
所以我大胆猜测其内部实现
- (NSString *)description {
return [NSString
stringWithFormat:@
"<%@:%p>", NSStringFromClass([
self
class]),&self];
}
注
:这是写框架的一些细节, 可以让使用者通过打印的方式更加具体的看到当前对象的一些状态.
D.NSURLSessionConfiguration
NSURLSessionConfiguration
系统提供了三种配置
[1]Configuration options for an NSURLSession. When a session is created, a copy of the configuration object is made - you cannot modify the configuration of a session after it has been created.
// 在创建Session对象时,可以通过NSURLSessionConfiguration对象来配置Session.
Session一旦配置完毕,你就不能够修改.
[2]The shared session uses the global singleton credential, cache
and cookie storage objects.
// Default Session 将cache以及credentials存储于本地。
[3]An ephemeral session has no persistent disk storage for cookies,
cache or credentials.
// Ephemeral Session 则对数据更加保密安全一些,
它不会向本地存储任何信息,所有的cache、credentials 等存在内存中并和Session绑定,
当Session销毁时,所有的相关信息也同时自动销毁。
[4]A background session can be used to perform networking operations on behalf of a suspended application, within certain constraints.
// Background Session能够使APP处于后台时,数据继续传输。
其行为与default Session类似,但是所有的数据传输均有一个独立的进程来管理(非本APP)。
同时Background Session也有一些功能上的限制。
下面三种配置的接口提供
@interface NSURLSessionConfiguration : NSObject <NSCopying>
@property (
class,
readonly,
strong)
NSURLSessionConfiguration *defaultSessionConfiguration;
@property (
class,
readonly,
strong)
NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (
NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(
NSString *)identifier API_AVAILABLE(macos(
10.10), ios(
8.0), watchos(
2.0), tvos(
9.0));
二、AFURLSessionManager
AFURLSessionManager
这个类才是对请求发送的核心类.它主要包括AFURLSessionManagerTaskDelegate
、_AFURLSessionTaskSwizzling
、AFURLSessionManager
这三个对象.
<一>AFURLSessionManagerTaskDelegate
这个类分发处理了AFURLSessionManager
主类的上传,下载进度的管理,通过观察task一些方法的变化,来得到进度.而且还帮忙处理了NSURLSessionTaskDelegate
、NSURLSessionDataTaskDelegate
和NSURLSessionDownloadTaskDelegate
等代理的返回数据.
A.NSProgress
// 进度暂停回调
@property (
nullable,
copy)
void (^pausingHandler)(
void);
// 进度恢复回调
@property (
nullable,
copy)
void (^resumingHandler)(
void)
NS_AVAILABLE(
10_11,
9_0);
注:AFNetworking 对进度的管理也用到了
NSProgress,并实现了进度的暂停及恢复.
这里对NSProgress
已经做了详细的介绍我不再多做解释.
<二>_AFURLSessionTaskSwizzling
这个类在#issues 1477上reopen了多次,讨论还是很激烈的。讨论的起由是app会莫名crash,主要原因是AFNetworking对NSURLSessionTask中的state进行了KVO操作。一开始人们removeObserver这个state,但是会造成AFNetworkActivityIndicatorManager功能(其中会观察state)削弱。另外后来iOS8上也出现了同样crash现象,貌似iOS7和iOS8在NSURLSessionTask有些不同。最后还是有个大神用swizzling方法才解决了这个问题。
A.任务状态监听
AFNetworking
巧妙的运用runtime的方法交换在+load
中给NSURLSessionTask
的两个方法注入监听.
- (void)suspend;
- (void)resume;
![](https://i-blog.csdnimg.cn/blog_migrate/811cabb340fafb388149abb859408c86.webp?x-image-process=image/format,png)
- (
void)af_resume {
NSAssert([
self respondsToSelector:
@selector(state)],
@"Does not respond to state");
NSURLSessionTaskState state = [
self state];
[
self af_resume];
if (state !=
NSURLSessionTaskStateRunning) {
// 这有点不明白这个讨论恒成立state = NSURLSessionTaskStateCanceling;
// 发送重新开始通知 用于网路指示器的设置
[[
NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:
self];
}
}
<三>AFURLSessionManager
A.NSURLSession与NSURLConnection
1.
NSURLSession在iOS7
.0时被Apple提出后, 虽然Apple一直对其良好的API设计大力推广,
然而其能够达到的效果, 似乎一直都和
NSURLConnection不相伯仲.
2.由于AFNetworking优秀的架构设计,
NSURLSession甚至还不如
NSURLConnection好用.
那么,有什么理由切换到
NSURLSession?
2015年的WWDC似乎告诉了我们答案.
3.HTTP /
2,
2015年
5月RFC
7540正式发表的下一代HTTP协议,
是
1999年来HTTP
1.1发布后的首个更新. 相对于前一个版本, HTTP /
2以快著称.
![](https://i-blog.csdnimg.cn/blog_migrate/22bf454c7ba5021cd5fbc4c43e38dd18.webp?x-image-process=image/format,png)
根据2015的WWDC Session71,我们知道iOS9+,
NSURLSession
开始正式支持HTTP /2,也就意味着你的网络连接速度也可以有如上图那样的提升。 B.共享NSURLSession思路分析
- 现在
AFNetworking
内部提供的创建方式[AFHTTPSessionManager manager]
,每次调用会新建一个NSURLSession,然后新建Task,激活Task,完成网络请求。
在回答这个问题以前,我们先来聊聊网络的通讯协议。
我们也都知道,HTTP协议是基于TCP协议的。所以在每次的HTTP请求之前,客户端和服务器端,
都先需要经过TCP连接的三次握手,即每次请求之前,
网络的数据都已经在客户端和服务器端之间来回了三次。如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/64b6384ec378cdff4e55d18e5c78b8c4.webp?x-image-process=image/format,png)
事实上在
HTTP 0
.9,
HTTP 1
.0协议的时代,
每次
HTTP的请求,都需要先经过
TCP的连接,然后才开始
HTTP的请求.
那么,为了让我们的请求更快,避免每次都产生一个
TCP三次握手,成了一个优化的选项。
于是在
HTTP 1
.1中,出现了
Connection:
keep-alive这个选项。这个优化选项,
可以使得客户端和服务器端复用一个
TCP连接,从而减小每次的网络请求时间。
没错,共享的
NSURLSession
将会复用TCP的连接,而每次都新建
NSURLSession
的操作将导致每次的网络请求都开启一个TCP的三次握手。所以我们封装请求类的时候,最好用单例模式.让
manager
持有NSURLSession
,达到共享的效果.即一个Session
创建多个Task
来实现网路的请求.
B.delegate的储存
self.mutableTaskDelegatesKeyedByTaskIdentifier
是一个储存
AFURLSessionManagerTaskDelegate
的可变字典.用NSLock锁保证了线程安全.
![](https://i-blog.csdnimg.cn/blog_migrate/0903f40335bfddbc1d05362c77dcc9ec.webp?x-image-process=image/format,png)
C. responseSerializer
/**
当数据传输任务用“GET”、“POST”等方式时,在“dataTaskWithRequest:success:failure:”方法里创建的一个从服务器发回的响应。
默认情况下,此属性设置为“AFJSONResponseSerializer”的一个实例。
@warning “responseSerializer”必须不为空.
*/
@property (
nonatomic,
strong)
id <AFURLResponseSerialization> responseSerializer;
AFHTTPRequestSerializer
和
AFHTTPResponseSerializer
都遵循了
<AFURLResponseSerialization>
协议.
为什么这里提到这个呢, 这种通过协议来整合不同工具的方法,很值得借鉴. 在以后的文章中会详细介绍这两个类.
谢谢观赏。