Hello, World!

AFNetworking解析

字数统计: 1.4k阅读时长: 7 min
2018/10/22 Share

框架结构

NSURLSession

1
2
3
AFURLSessionManager

AFHTTPSessionManager (使用入口,父类是AFURLSessionManager)

Serialization

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

<AFURLRequestSerialization>

AFHTTPRequestSerializer

AFJSONRequestSerializer (父类是AFHTTPRequestSerializer)

AFPropertyListRequestSerializer (父类是AFHTTPRequestSerializer)

<AFURLResponseSerialization>

AFHTTPResponseSerializer

AFJSONResponseSerializer (父类是AFHTTPResponseSerializer)

AFXMLParserResponseSerializer (父类是AFHTTPResponseSerializer)

AFXMLDocumentResponseSerializer (macOS) (父类是AFHTTPResponseSerializer)

AFPropertyListResponseSerializer (父类是AFHTTPResponseSerializer)

AFImageResponseSerializer (父类是AFHTTPResponseSerializer)

AFCompoundResponseSerializer (父类是AFHTTPResponseSerializer)

Additional Functionality

1
2
3
AFSecurityPolicy

AFNetworkReachabilityManager

第一步

使用AFNetworking的第一步,就是创建AFHTTPSessionManager对象,方式如下:

1
AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];

AFHTTPSessionManager继承自AFURLSessionManager。
这句代码完成了如下工作:
1,在AFURLSessionManager类中:

1
2
3
4
5
6
// 属性
1,sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
2,operationQueue = [[NSOperationQueue alloc] init];
operationQueue.maxConcurrentOperationCount = 1;
3,session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:operationQueue];
4,securityPolicy = [AFSecurityPolicy defaultPolicy];

2,在AFHTTPSessionManager类中:

1
2
3
// 属性
1,requestSerializer = [AFHTTPRequestSerializer serializer];
2,responseSerializer = [AFJSONResponseSerializer serializer];

第二步

第二步调用POST方法
POST方法功能: 1.获取NSURLRequest实例。2.获取NSURLSessionDataTask实例。3.开启任务。
POST方法实现了网络请求的整个流程。

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
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
// 1.获取NSURLRequest实例
NSError *serializationError = nil;
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;
}

// 2.获取NSURLSessionDataTask实例
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(task, error);
}
} else {
if (success) {
success(task, responseObject);
}
}
}];

// 3.开启任务
[task resume];

return task;
}

NSURLRequest创建过程

创建NSURLRequest实例的过程,主要与
AFHTTPRequestSerializer、
AFStreamingMultipartFormData、
AFMultipartBodyStream、
AFHTTPBodyPart
类有关。

它们之间的关系如下如所示:
AFN

在AFHTTPRequestSerializer类中创建NSMutableURLRequest实例,代码如下:

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
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]);

// 1 根据url创建一个NSMutableURLRequest实例,并且配置了HTTPMethod
NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error];

// 2 创建AFStreamingMultipartFormData实例,并把NSMutableURLRequest实例作为属性。
__block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding];

// 3 把请求参数(非文件数据)传递给AFStreamingMultipartFormData实例。
if (parameters) {
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
NSData *data = nil;
if ([pair.value isKindOfClass:[NSData class]]) {
data = pair.value;
} else if ([pair.value isEqual:[NSNull null]]) {
data = [NSData data];
} else {
data = [[pair.value description] dataUsingEncoding:self.stringEncoding];
}

if (data) {
[formData appendPartWithFormData:data name:[pair.field description]];
}
}
}

// 4 把请求参数(文件数据)传递给AFStreamingMultipartFormData实例。
if (block) {
block(formData);
}

// 5 此步骤之前,拼接表单所需要的全部数据都保存在了AFStreamingMultipartFormData实例中。
// 给NSMutableURLRequest实例配置HTTPBodyStream和HTTPHeaderField
return [formData requestByFinalizingMultipartFormData];
}

第1步的作用是,根据url创建一个NSMutableURLRequest实例,并且配置了HTTPMethod。
第2+3+4四步的作用是,把拼接表单所需要的全部数据都保存在AFStreamingMultipartFormData实例中,且把NSMutableURLRequest实例传递过去。
第5步的作用是,给NSMutableURLRequest实例配置HTTPBodyStream和HTTPHeaderField。

在AFStreamingMultipartFormData类中,拼接表单的数据都以AFHTTPBodyPart实例形式保存在属性bodyStream的HTTPBodyParts数组中。代码如下

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
// 1
- (void)appendPartWithFormData:(NSData *)data
name:(NSString *)name
{
NSParameterAssert(name);

NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
[mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"];

[self appendPartWithHeaders:mutableHeaders body:data];
}

// 2
- (void)appendPartWithHeaders:(NSDictionary *)headers
body:(NSData *)body
{
NSParameterAssert(body);

AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
bodyPart.stringEncoding = self.stringEncoding;
bodyPart.headers = headers;
bodyPart.boundary = self.boundary;
bodyPart.bodyContentLength = [body length];
bodyPart.body = body;
// AFMultipartBodyStream
[self.bodyStream appendHTTPBodyPart:bodyPart];
}

// 3
- (NSMutableURLRequest *)requestByFinalizingMultipartFormData {
if ([self.bodyStream isEmpty]) {
return self.request;
}

// Reset the initial and final boundaries to ensure correct Content-Length
[self.bodyStream setInitialAndFinalBoundaries];
[self.request setHTTPBodyStream:self.bodyStream];

[self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"];
[self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"];

return self.request;
}

根据方法1和2可知,表单数据保存在AFHTTPBodyPart实例中,AFHTTPBodyPart实例保存在属性bodyStream内部的数组中。
根据方法3可知,给NSMutableURLRequest实例设置HTTPBodyStream和HTTPHeaderField的值。

AFMultipartBodyStream是继承自NSInputStream类,重写内部方法read:maxLength:实现表单拼接。代码如下:

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
- (void)open {
if (self.streamStatus == NSStreamStatusOpen) {
return;
}

self.streamStatus = NSStreamStatusOpen;

[self setInitialAndFinalBoundaries];
// 把AFHTTPBodyPart数组,转换成枚举
self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator];
}


- (NSInteger)read:(uint8_t *)buffer
maxLength:(NSUInteger)length
{
if ([self streamStatus] == NSStreamStatusClosed) {
return 0;
}

NSInteger totalNumberOfBytesRead = 0;

while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) {
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
break;
}
} else {
NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead;
// 调用AFHTTPBodyPart实例的read:maxLength:,拼接表单
NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength];
if (numberOfBytesRead == -1) {
self.streamError = self.currentHTTPBodyPart.inputStream.streamError;
break;
} else {
totalNumberOfBytesRead += numberOfBytesRead;

if (self.delay > 0.0f) {
[NSThread sleepForTimeInterval:self.delay];
}
}
}
}

return totalNumberOfBytesRead;
}

由代码可知,AFMultipartBodyStream中的read:maxLength:方法并不是真正做表单拼接的地方,真正的地方在AFHTTPBodyPart实例的read:maxLength:方法中。

在AFHTTPBodyPart类中,实现了真正的表单拼接。

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
// 1
- (NSInteger)read:(uint8_t *)buffer
maxLength:(NSUInteger)length
{
NSInteger totalNumberOfBytesRead = 0;

if (_phase == AFEncapsulationBoundaryPhase) {
NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding];
totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
}

if (_phase == AFHeaderPhase) {
NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding];
totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
}

if (_phase == AFBodyPhase) {
NSInteger numberOfBytesRead = 0;

numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
if (numberOfBytesRead == -1) {
return -1;
} else {
totalNumberOfBytesRead += numberOfBytesRead;

if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) {
[self transitionToNextPhase];
}
}
}

if (_phase == AFFinalBoundaryPhase) {
NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]);
totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)];
}

return totalNumberOfBytesRead;
}

// 2
- (NSInteger)readData:(NSData *)data
intoBuffer:(uint8_t *)buffer
maxLength:(NSUInteger)length
{
NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length));
[data getBytes:buffer range:range];

_phaseReadOffset += range.length;

if (((NSUInteger)_phaseReadOffset) >= [data length]) {
[self transitionToNextPhase];
}

return (NSInteger)range.length;
}

核心代码是方法2中的[data getBytes:buffer range:range];

NSURLSessionDataTask创建过程

创建NSURLSessionDataTask实例的过程,主要与
AFURLSessionManager
类有关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
__block NSURLSessionUploadTask *uploadTask = nil;
url_session_manager_create_task_safely(^{
// self.session在初始化方法中已经创建好了。
uploadTask = [self.session uploadTaskWithStreamedRequest:request];
});

[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];

return uploadTask;
}

CATALOG
  1. 1. 框架结构
  2. 2. 第一步
  3. 3. 第二步
    1. 3.1. NSURLRequest创建过程
    2. 3.2. NSURLSessionDataTask创建过程