AFNetworking基本模块

AFNetworking主要分为5个模块

  • 通信模块(AFURLSessionManager, AFHTTPSessionManager)
  • 网络状态监听
  • 安全模块
  • 通信序列化/反序列化模块
  • UIKit相关

实际上AFNetworking是对原生的NSURLSession进行的封装,上面所说的四个部分并不是并列的关系,所有请求逻辑全部交由AFURLSessionManager来处理,其他的网络监听,安全和序列化/反序列化全是为AFURLSessionManager服务或者说是以其为基础的。至于AFHTTPSessionManager本身也是继承自URLSessionManager的一层封装,本身并不干活,只是将请求逻辑分发给其父类去做。

如上所说,用户对接的其实是AFHTTPSessionManager类,当需要实例化网络请求的时候,一般使用下面的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration
*)configuration;
其中
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// 对传进来的url进行判断,判断结束是否有“/”
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}

而其实这个初始化的调用,也是先调用了父类AFURLSessionManager的初始化方法,这个后面再说。

在AFHTTPSessionManager中,基本是

1
2
3
4
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure

这样的方法,将GET,POST,PUT,DELETE等指令全部包装起来,交给AFURLSessionManager来完成。一般都很简单地只是将请求交给父类,获取对应的NSURLSessionTask然后调用其resume方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
// 正式开始网络请求
[dataTask resume];
return dataTask;
}

比如这个GET方法的包装,就是这样一个流程。
AFHTTPSessionManager还有另一个功能就是把调用者发起得请求转换编码成最后需要的request,然后再由父类进行真正的网络请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure{
NSError *serializationError = nil;
// 将需要的部件放到一起组成一个request
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
if (serializationError) {
if (failure) {
// 如果解析错误就直接返回
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
// 若成功则用这个request生成一个dataTask实例交给回调方法
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
}

如上面的代码就是调用转化编码的请求,如果没有报错,那么后续就会对这个request作为参数来发起网络请求。

序列/反序列RequestSerialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
// 通过url来创建一个request实例
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
// 将HTTP请求类型作为参数赋给request
mutableRequest.HTTPMethod = method;
// 循环参数列表
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
// 将parameters编码之后交给request
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}

上面就是初始化一个request的对应方法,值得一说的是,将parameter进行编码的部分,本质是将本来包含了各种dictionary以及array的完整dictionary中的所有参数全部“拉伸”开来变成一个字符串,然后根据网络请求的类型来决定是将这个字符串参数放到URL后面还是直接封装到HTTP请求体body中。
补充一下其中具体的细节:

1
2
3
4
5
6
7
8
9
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
});
return _AFHTTPRequestSerializerObservedKeyPaths;
} // 这是一个C的函数,本质就是封装了一些属性的名字

mutableObservedChangedKeyPaths是类的一个属性,负责将RequestSerializer类和NSURLRequest的相关属性进行KVO监听:

具体的实现机制就是在init时初始化一个mutableObservedChangedKeyPaths空的set,并且为AFHTTPRequestSerializerObservedKeyPaths()中所有属性同名的set方法添加oberser。然后每当set方法被调用的时候就添加到mutableObservedChangedKeyPaths中,这样其实我们很容易看出来循环参数列表的作用:就是将可能调用的request属性中确实调用了的部分给取出来作为一个数组。

具体编码方法

然后所有元素都有了,剩下来的就是具体的编码方法了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
// 补全request对象,使用httpheader这个参数
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
// 对参数parameter进行编码
NSString *query = nil;
if (parameters) {
// 如果存在自定义的解析方法就直接调用
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
} else { // 否则使用默认的方法
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
// 将编码完成的参数和URL合并起来,或者作为HTTP的body。判断该request中是否包含了GET、HEAD、DELETE(都包含在HTTPMethodsEncodingParametersInURI)。因为这几个method的quey是拼接到url后面的。而POST、PUT是把query拼接到http body中的
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
} else {
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}

上面可以看到,对一个request进行编码的流程首先是根据已有的HTTPRequestHeaders这个参数来对request的参数进行补全,HTTPRequestHeaders是一个dictionary,首先遍历这个dictionary,如果request这个URLRequest对象不包含某个key,那么就添加一个对应的键值对给它。
然后是最重要的,query的编码部分,顺着query = AFQueryStringFromParameters(parameters) 这个部分找下去可以找到最终的编码规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
return [mutablePairs componentsJoinedByString:@"&"];
}
NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
}
NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
// Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}

先将parameter整个dictionary进行处理,上面最后一个方法是一个递归调用,如果参数是dictionary,那么对其中每一个元素进行拆分,得到一个dic[key]=value这样的对,并保存在一个临时数组中;如果参数是数组,那么拆分后得到array[]= value这样的对,也保存在临时数组中…这样将parameter中所有最小元素全部拆分成为键值对保存在一个最终的数组中之后,便利数组,每个对间隔插入“&”,最后成为一个字符串,就是最终网络请求使用的query。

具体变化如下:

1
2
3
4
5
6
7
8
9
@{
@"name" : @"heqian",
@"phone": @{@"mobile": @"123", @"home": @456},
@"game": @[@"dark souls", @"tales of zelda"],
@"nums": [NSSet setWithObjects:@"1", @"2", nil]
}
最终会变化为
name=heqian&phone[mobile]=123&phone[home]=456&game[]=dark souls&game[]=tales of zelda
&nums=1&num=2

完成query的编码之后,根据请求的种类,来判断是直接拼接在URL之后,还是应该放在HTTP请求的body中。

AFURLSessionManager核心解析

初始化方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
// queue并发线程设置为1
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// 设置delegate,等于是包装了一次NSURLSession,它所需要的代理全部交给AFURLSessionManager来处理
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
// 响应转码
self.responseSerializer = [AFJSONResponseSerializer serializer];
// 安全策略
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
// 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// 加锁,防止线程冲突
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
// 将task关联的代理全部置为空
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}

基本是很普通的对参数的初始化,值得说明的是(1)self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init] 这个dictionary,在AFNetworking中每一个task都会匹配一个taskDelegate来做task的事件处理,上面的处理中在创建了dictionary之后还创建了对应的NSLock,理所当然是为了保证多线程的情况下操作dictionary不会发生错误 (2)为什么要清空session中的所有task,我们知道在初始化的时候session中应该不会有任何task才对。但是实际上后台也在运行一个session,当任务从后台的session返回的时候,是可以重新恢复到session中的,只要对应的ID相同。所以有这么一种可能,创建了新的session之后,后台session返回了刚刚处理完的task,然后无意中填充到这个新的session中,这样的情况下,我们就必须清空所有task。

之前在序列化中提到有一系列方法能返回task:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
__block NSURLSessionDataTask *dataTask = nil;
// 这里因为IOS8以下存在一个BUG,在并发队列中创建task可能导致不正确的completionHandlers回调,[#2093]( https://github.com/AFNetworking/AFNetworking/issues/2093 “#2093”),这里直接做了串行处理,保证每个task的completionHandler都是正确的
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}

基本上这类的方法都是两个步骤:(1)调用session方法,通过request参数来生成task,上面的串行处理url_session_manager_create_task_safely只是一个判断系统是否会出现BUG的一个包装而已,如果是IOS8以上(包括8),不存在这个BUG那么就可以直接执行。
(2)给每个task对象创建一个对应的delegate,实际上这个delegate系统是整个类中最核心的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
// 为dataTask生成一个对应的taskDelegate,并且由AFURLSessionManager自己来管理
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;
// 关键元素taskDescriptionForSessionTasks用来发送开始和挂起通知时用到,这就是task和manager的关联纽带
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
// 将delegate对象与dataTask建立关系
[self setDelegate:delegate forTask:dataTask];
// 设置delegate的两个进度block
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
// 加锁保证线程安全
[self.lock lock];
// dictionary以taskIdentifier作为key,将delegate放入其中
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 添加task到nofification中,监听其动态
[self addNotificationObserverForTask:task];
// 解锁
[self.lock unlock];
}

以上就主要作用是把task和其代理建立起关联,并且保存在manager的字典中,
到这里准备工作就做好了,之前在AFHTTPSessionManager中我们看到,返回一个task之后,直接调用了resume方法,其实就是开启了任务
而在初始化方法中

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

其实是把AFURLSessionManager作为了所有task的delegate。

我们可以看到AFURLSessionManager自己完成了4个delegate的实现

1
2
3
4
NSURLSessionDelegate
NSURLSessionTaskDelegate
NSURLSessionDataDelegate
NSURLSessionDownloadDelegate

这样就将复杂的NSURLSession的各种delegate做了一个综合的处理,最后通过AFURLSessionManager转发到自定义delegate的方法就变得非常清晰了,只有比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}


1
2
3
4
5
6
7
8
9
10
11
12
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}

这样的方法中会需要将消息转发出去让自定义的delegate来完成。值得一提的是,这些protocol并不是并列的关系
在NSURLSession的声明文件中我们可以看到,NSURLSessionDelegate 继承自NSObject,而NSURLSessionTaskDelegate继承自NSURLSessionDelegate,另外三个protocol则全部继承自NSURLSessionTaskDelegate。那么当一个delegate需要执行操作的时候,它会通过这个继承的顺序依次查找protocol的实现,另外AFNetworking重写了respondsToSelector:(SEL)selector这个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
- (BOOL)respondsToSelector:(SEL)selector {
if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
return self.taskWillPerformHTTPRedirection != nil;
} else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
return self.dataTaskDidReceiveResponse != nil;
} else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
return self.dataTaskWillCacheResponse != nil;
} else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
return self.didFinishEventsForBackgroundURLSession != nil;
}
return [[self class] instancesRespondToSelector:selector];
}

上面的self.taskWillPerformHTTPRedirection,self.dataTaskDidReceiveResponse等全是自定义的回调block,如果没有对block进行赋值,那么方法回调也没有什么意义。
在AFURLSessionManager中声明了许多这样的block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;

它们通过set方法进行赋值(这样的好处在于,使用者可以通过set方法的接口来了解对应block需要的参数)

AFNetworking好处

由于苹果推出的NSURLSession帮助我们完成了任务的调度功能,所以AFNetworking3.0不像2.0的时候一样有了那么多的底层功能,但是实际上它还是完成了很多能节省开发者大量时间的任务。比如request拼接,请求的格式转换,各种delegate的封装,并且在完成任务之后的回调上进行了很多判断。如果这些工作全部交给开发者自己在NSURLSession的基础上完成,那么毫无疑问工作量会大大增加。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器