善恶众相

  • 首页

  • 分类

  • 归档

AFNetworking2.0源码分析(原创)

发表于 2015-05-30 更新于 2019-08-07 分类于 iOS
基于线程的组织结构去介绍AFNetworking请求发出的过程

做为iOS的开发者对于AFNetworking肯定不陌生,本文从代码流程的角度去窥探AFNetworking做了什么。

AFNetworking目录结构请参阅作者的这篇文章

由于NSURLSession只支持iOS 7以后,所以为了向下兼容我们看一下利用NSURLConnection创建请求的过程。

请求的创建与设置

我们以创建一个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
[[AFHTTPRequestOperationManager manager] POST:@"http://url"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {}];

// AFHTTPRequestOperationManager.m
- (AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// 设置URLRequest的URL,method,httpHeader,httpBody
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST"
URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString]
parameters:parameters error:nil];


AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request
success:success
failure:failure];

[self.operationQueue addOperation:operation];

return operation;
}

首先我们通过AFHTTPRequestSerializer的requestWithMethod:URLString:parameters:方法获取一个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
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSURL *url = [NSURL URLWithString:URLString];

// 设置请求地址,请求方法此处为POST请求
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;

// 设置KVO监听的变量
// allowsCellularAccess,cachePolicy,HTTPShouldHandleCookies,HTTPShouldUsePipelining,networkServiceType,timeoutInterval
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}

// 设置httpHeader和httpBody
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

return mutableRequest;
}

继续跟进requestBySerializingRequest:withParameters:error:方法:

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
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSMutableURLRequest *mutableRequest = [request mutableCopy];

// 设置URLRequest的httpHeader
//{"Accept-Language":"en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5",
//"User-Agent":"AFNetworking iOS Example/1.0.0 (iPhone Simulator; iOS 8.3; Scale/2.00)"}
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];

if (parameters) {
NSString *query = nil;
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 = AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding);
break;
}
}

// 如果是HTTPMethod是GET HEAD DELETE中的一种 则直接在URL中拼接参数
// 如果是其他类型HTTPMehtod则将参数封装在HTTPBody中
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
} else {
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
}

return mutableRequest;
}

创建完NSMutableURLRequest后,通过AFHTTPRequestOperation的HTTPRequestOperationWithRequest:success:failure:方法,初始化成员变量以及请求成功和失败的block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = self.responseSerializer;
operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage;
operation.credential = self.credential;
operation.securityPolicy = self.securityPolicy;

[operation setCompletionBlockWithSuccess:success failure:failure];
operation.completionQueue = self.completionQueue;
operation.completionGroup = self.completionGroup;

return operation;
}

查看一下请求成功和失败的回调,跟进setCompletionBlockWithSuccess:failure:方法:

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
58
59
60
61
62
63
64
65
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
// 此处调用父类的setCompletionBlock:方法
self.completionBlock = ^{
if (self.completionGroup) {
dispatch_group_enter(self.completionGroup);
}

dispatch_async(http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
success(self, responseObject);
});
}
}
}

if (self.completionGroup) {
dispatch_group_leave(self.completionGroup);
}
});
};
}

// 父类AFURLConnectionOperation的
- (void)setCompletionBlock:(void (^)(void))block {
[self.lock lock];
if (!block) {
[super setCompletionBlock:nil];
} else {
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;

dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();

dispatch_group_async(group, queue, ^{
block();
});
// 确保传入的block执行完之后再去调用NSOperation的完成回调
dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];
}
[self.lock unlock];
}

其中:

1
2
3
4
5
6
7
8
9
10
11
dispatch_group_async(group, queue, ^{ 
  // ...
});

// 等价于:

dispatch_group_enter(group);
dispatch_async(queue, ^{
  //...
  dispatch_group_leave(group);
});

最终AFURLConnectionOperation类的completionBlcok最终将执行如下代码:

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
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;
// 确保成功或失败的数据及界面的处理在主线程的queue中进行
dispatch_group_async(url_request_operation_completion_group(), dispatch_get_main_queue(), ^{
dispatch_group_async(self.completionGroup, http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(http_request_operation_completion_group(), dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(http_request_operation_completion_group(), dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_group_async(http_request_operation_completion_group(), dispatch_get_main_queue(), ^{
success(self, responseObject);
});
}
}
}
});
});
// 确保传入的block执行完之后再去调用NSOperation的完成回调
dispatch_group_notify(url_request_operation_completion_group(), url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];

通过以上代码可以看出:

  • 成功或失败的回调都是在主线程的队列中执行的
  • 通过dispatch_group_notify方法确保,成功或失败的回调执行完成后才去执行,NSOperation自己的完成block。

最后一步是将创建的AFHTTPRequestOperation对象添加到operationQueue中等待系统调度执行。

Operation的执行过程

接下来我们分析一下请求的执行过程:

首先,一个NSOperation被添加进NSOperationQueue中之后,当系统调度执行该Operation时,首先从start方法开始执行:

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
// 将每一个connection放到同一个线程networkRequestThread中去执行 保证每一个请求的处理都是顺序执行的
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;

[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}

- (void)operationDidStart {
[self.lock lock];
if (![self isCancelled]) {
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
// 将connection和outputStream添加到当前runloop的指定mode中去运行
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}

[self.connection start];
}
[self.lock unlock];

dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
});
}

我们看到在start函数中将operationDidStart方法加到networkRequestThread的线程的runloop中去执行,而operationDidStart方法将connection和ouputStream作为事件源填加到当前线程(networkRequestThread线程)的runloop中,然后runloop就会监听NSURLConnection的处理回调,当事件发生时调用对应的代理去处理,在接收请求数据过程中使用了outputStream,等到请求完成再将outputStream中的数据传递给responseData:

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
58
59
60
- (void)connection:(NSURLConnection __unused *)connection
didReceiveResponse:(NSURLResponse *)response
{
// 当接收到response的时候打开outputStream准备将接收的数据写入其中
self.response = response;

[self.outputStream open];
}

- (void)connection:(NSURLConnection __unused *)connection
didReceiveData:(NSData *)data
{
NSUInteger length = [data length];
while (YES) {
NSInteger totalNumberOfBytesWritten = 0;
if ([self.outputStream hasSpaceAvailable]) {
const uint8_t *dataBuffer = (uint8_t *)[data bytes];

NSInteger numberOfBytesWritten = 0;
while (totalNumberOfBytesWritten < (NSInteger)length) {
numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
if (numberOfBytesWritten == -1) {
break;
}

totalNumberOfBytesWritten += numberOfBytesWritten;
}

break;
}

if (self.outputStream.streamError) {
[self.connection cancel];
[self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError];
return;
}
}

dispatch_async(dispatch_get_main_queue(), ^{
self.totalBytesRead += (long long)length;

if (self.downloadProgress) {
self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
}
});
}

- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
// 将ouputStream中接收的数据赋值给responseData
self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];

[self.outputStream close];
if (self.responseData) {
self.outputStream = nil;
}

self.connection = nil;

[self finish];
}

整体的流程结构如下图:

需要注意的是:

  • 首先请求operation添加到operationQueue中,这些operation的执行关系是并行的
  • 每一个operation执行的任务是向networkRequestThread线程中添加任务operationDidStart,也就是说:[向networkRequestThread线程中添加任务operationDidStart的过程]是并行的
  • 每一个operationDidStart任务的工作又是向networkRequestThread线程中添加connection和outputStream两个事件源
  • 由于operationDidStart任务以及connection、outputStream事件源都是被添加到同一个networkRequestThread线程中的,所以这三者之间的执行关系是串行的,也就是说networkRequestThread线程的runloop的轮询的执行operationDidStart任务以及监听connection、outputStream事件源并做出处理这三者是串行的关系

延伸应用

设想以下场景:当进入一个界面的时候我们需要发送4个请求,而第4个请求的发出依赖于前3个请求的完成,这时候就需要对着几个请求进行一些同步操作,如果利用GCD的话我们首先想到的是利用dispatch group将前三个请求放到group中等到全部执行完成后再去执行第4个请求,再进一步我们如果想要记录前3个请求的完成情况的话又该怎么办呢,其实AFNetworking的AFURLConnectionOperation.m已经为我们提供了batchOfRequestOperations方法,为了能够对请求完成情况进行记录,使用了一些技巧请参见注释,方法如下:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
+ (NSArray *)batchOfRequestOperations:(NSArray *)operations
progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock
{
if (!operations || [operations count] == 0) {
return @[[NSBlockOperation blockOperationWithBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(@[]);
}
});
}]];
}

__block dispatch_group_t group = dispatch_group_create();
// 当最后一个operation请求返回后
// 异步的执行targetBlock与batchedOperation轮询到最后一个operation已经执行完成后执行batchedOperation的block之间存在竞争关系

// 当targetBlock先执行后,加入group中的最后一个block调用dispatch_group_leave
// 之后batchedOperation轮询到最后一个operation已经执行完成,执行batchedOperation的block
// 执行dispatch_group_notify时,不会阻塞直接执行

// 当batchedOperation先轮询到最后一个operation完成,会立即执行下面的block
// 执行dispatch_group_notify时,由于batchedOperation未执行,会阻塞再此等待batchedOperation执行完dispatch_group_leave后
// 才会继续执行completionBlock
NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(operations);
}
});
}];

for (AFURLConnectionOperation *operation in operations) {
operation.completionGroup = group;
void (^originalCompletionBlock)(void) = [operation.completionBlock copy];
__weak __typeof(operation)weakOperation = operation;
operation.completionBlock = ^{
__strong __typeof(weakOperation)strongOperation = weakOperation;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_queue_t queue = strongOperation.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
// 暂且把下面dispatch_group_async中的block称之为targetBlock
// 请求返回后operation的completionBlock会立即返回
// 异步的去执行targetBlock的内容
dispatch_group_async(group, queue, ^{
if (originalCompletionBlock) {
originalCompletionBlock();
}

// 由于operation的completionBlock立即返回它的isFinished标识已标记为YES
NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) {
return [op isFinished];
}] count];

if (progressBlock) {
progressBlock(numberOfFinishedOperations, [operations count]);
}

dispatch_group_leave(group);
});
};

dispatch_group_enter(group);
[batchedOperation addDependency:operation];
}

return [operations arrayByAddingObject:batchedOperation];
}
OC知识要点
Mach-O文件格式与otool工具的使用
  • 文章目录
  • 站点概览
Zrongl

Zrongl

23 日志
3 分类
GitHub E-Mail
  1. 1. 请求的创建与设置
  2. 2. Operation的执行过程
  3. 3. 延伸应用
© 2019 Zrongl
不争无尤
|
主题 – NexT.Mist v7.3.0
0%