AFNetWorking 深度理解

原文出处http://wmf00032.github.io/2016/07/12/afnetworking-know-what/

大家都看见了网络请求其实有两种方式。一种是用AFHTTPRequestOperationManager ,另一种是用AFHTTPSessionManager。那么这两种有什么区别尼?

估计又的人有所不知,AFNetworking最初的版本使用的就是AFHTTPRequestOperationManager 以就是自己自定义NSOperation的封装实现的。AFHTTPSessionManager是在2.0以后才引入进来的。以就是说在2.0之前,都是使用AFHTTPRequestOperationManager。

AFHTTPSessionManager 继承自 AFURLSessionManager,而AFURLSessionManager主要是使用系统提供的 NSURLSession和NSURLSessionTask进行网络操作的。我们看一下官方文档对这两个类的描述:

1
2
3
4
5
6
7
8
9
NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
@interface NSURLSession : NSObject
/*

  • NSURLSessionTask - a cancelable object that refers to the lifetime
  • of processing a given request.
    */
    NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
    @interface NSURLSessionTask : NSObject
    是的,你没有看错,NSURLSession和NSURLSessionTask是iOS7以后才出现的,所以如果你想要适配到iOS6,那么请你乖乖的使用前者 进行网络请求。这就解释了为什么作者会把两种请求方式都放在这儿。

下面分两部分进行网络AFNetworking网络请求的分析:
AFHTTPRequestOperationManager 部分的网络请求原理:

AFHTTPRequestOperationManager的init方法是这样的:

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

  • (instancetype)initWithBaseURL:(NSURL *)url {
    self = [super init];
    if (!self) {
    return nil;
    }
    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
    url = [url URLByAppendingPathComponent:@""];
    }
    self.baseURL = url;
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.shouldUseCredentialStorage = YES;
    return self;
    }
    其中默认的请求方式和解析方式被设置了默认值:

1
2
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
当然用户可以修改这两个参数,指定自己的请求方式和解析方式。

下面以GET请求为例来说。
当用户发起一个GET请求,下面的方法会被掉用:

1
2
3
4
5
6
7
8
9
10
11

  • (AFHTTPRequestOperation *)GET:(NSString *)URLString
    parameters:(id)parameters
    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
    {
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];
    [self.operationQueue addOperation:operation];
    return operation;
    }
    其中[self.operationQueue addOperation:operation];就是将当前的任务放进操作队列。
    关键我们看看AFHTTPRequestOperation 里面都做了什么。

AFHTTPRequestOperation 是继承自AFURLConnectionOperation,AFURLConnectionOperation实现了各种代理:

@interface AFURLConnectionOperation : NSOperation

我们知道当一个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

  • (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) {
    [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
    [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
    }
    [self.outputStream open];
    [self.connection start];
    }
    [self.lock unlock];
    dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
    });
    }
    我们分析一下一上代码块,当AFURLConnectionOperation任务被正常启动的时候,下面的方法会被调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
operationDidStart方法会在[[self class] networkRequestThread]返回的线程中被调用。我们看看这是一个什么样的线程:

  • (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
    [[NSThread currentThread] setName:@"AFNetworking"];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
    [runLoop run];
    }
    }
  • (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
    _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
    [_networkRequestThread start];
    });
    return _networkRequestThread;
    }
    是的这个新的小线程命名为“AFNetworking”, 它在床见得时候就启动了一个人runloop事件循环,并添加了一个NSMachPort 空端口,改NSMachPort 仅仅只是一个空的端口其目的是用来维护runloop的执行不被退出。

operationDidStart 方法中的:

1
2
3
4
5
6
7
8
9
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
[self.outputStream open];
[self.connection start];
说明self.connection和self.outputStream周期性任务被绑定在当期的runloop的self.runLoopModes 模式中。(self.runLoopModes在初始化的时候被赋值为[NSSet setWithObject:NSRunLoopCommonModes])

行了,那么当网络请求数据到达的时候,数据是如何被接收到的尼,我想这一点才是大家最关心的。
网络请求是一个异步的过程,当网络请求数据流到达的时候,runloop监听到改事件源,CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION方法会被调用。之后CFNetwork的_NSURLConnectionDidReceiveData(_CFURLConnection, __CFData const, long, void const*)放会被调用获取到网络数据。与此同时NSURLConnectionInternal的_withActiveConnectionAndDelegate方法会被调用,本地代理被激活。AFURLConnectionOperation中的代理方法:

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

  • (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;
    } else {
    [self.connection cancel];
    if (self.outputStream.streamError) {
    [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);
    }
    });
    }
    被调用,通过以上代码中的:

1
2
3
4
5
6
7
8
9
NSInteger numberOfBytesWritten = 0;
while (totalNumberOfBytesWritten < (NSInteger)length) {
numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
if (numberOfBytesWritten == -1) {
break;
}
totalNumberOfBytesWritten += numberOfBytesWritten;
}
网络数据流被写入缓存。数据被写入缓存完成后,代理方法:

1
2
3
4
5
6
7
8
9
10
11
12

  • (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
    self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
    [self.outputStream close];
    if (self.responseData) {
    self.outputStream = nil;
    }
    self.connection = nil;
    [self finish];
    }
    会被调用后。我们追踪[self finish]; 看看它里面的实现:

1
2
3
4
5
6
7
8
9

  • (void)finish {
    [self.lock lock];
    self.state = AFOperationFinishedState;
    [self.lock unlock];
    dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
    });
    }
    self.state = AFOperationFinishedState这句代码是重点,它标示了该请求任务已经结束。而这句赋值还做了一个KVO的操作,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

  • (void)setState:(AFOperationState)state {
    if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
    return;
    }
    [self.lock lock];
    NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
    NSString *newStateKey = AFKeyPathFromOperationState(state);
    [self willChangeValueForKey:newStateKey];
    [self willChangeValueForKey:oldStateKey];
    _state = state;
    [self didChangeValueForKey:oldStateKey];
    [self didChangeValueForKey:newStateKey];
    [self.lock unlock];
    }
    NSOperationInternal中的_observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:方法会监听state状态的改变。然后回归到主线程,AFURLConnectionOperation中的setCompletionBlock方法被回调:

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

  • (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;

pragma clang diagnostic push

pragma clang diagnostic ignored "-Wgnu"

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

pragma clang diagnostic pop

        dispatch_group_async(group, queue, ^{
            block();
        });
        dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
            [strongSelf setCompletionBlock:nil];
        });
    }];
}
[self.lock unlock];

}
关键看这句代码:

1
2
3
dispatch_group_async(group, queue, ^{
block();
});
block()一调用就调用到了AFHTTPRequestOperation的方法:

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

pragma mark - AFHTTPRequestOperation

  • (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.

pragma clang diagnostic push

pragma clang diagnostic ignored "-Warc-retain-cycles"

pragma clang diagnostic ignored "-Wgnu"

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);
        }
    });
};

pragma clang diagnostic pop

}
self.completionBlock中的内容被执行,这里面最关键的一句id responseObject = self.responseObject 获得了解析数据,我们看看self.responseObject的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13

  • (id)responseObject {
    [self.lock lock];
    if (!_responseObject && [self isFinished] && !self.error) {
    NSError *error = nil;
    self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
    if (error) {
    self.responseSerializationError = error;
    }
    }
    [self.lock unlock];
    return _responseObject;
    }
    我靠!春天来了,这句代码:

1
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
将stream中的数据解析成了我们想要数据比如json、xml、plist等等。然后AFHTTPRequestOperation方法setCompletionBlockWithSuccess中代码success(self, responseObject)一回调。好了,现在就不用说了,我们通常就是在这个success block做我们自己的处理的。

下面我们看一下AFHTTPSessionManager 网络请求是怎么样进行的
苹果已经对NSURLSessionDataTask做了高度的封装,类似于AFURLConnectionOperation这样的复杂封装已经看不见了。但是原理跟AFURLConnectionOperation的差不多这里就不在赘述了。

到一个网络数据流到达的时候,NSURLSession的URLSession:dataTask:didReceiveData:方法就会被激活。AFURLSessionManager实现了NSURLSession的代理,于是乎AFURLSessionManager中的代理方法就会被调用:

1
2
3
4
5
6
7
8
9
10
11

  • (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 URLSession:session dataTask:dataTask didReceiveData:data]里面的实现四这样的:

1
2
3
4
5
6

  • (void)URLSession:(__unused NSURLSession *)session
    dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
    {
    [self.mutableData appendData:data];
    }
    这样网络数据就被写入了self.mutableData。
    当数据获取完成之后URLSession:task:didCompleteWithError:方法就会被调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

  • (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);
    }
    }
    我们看看 [delegate URLSession:session task:task didCompleteWithError: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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

  • (void)URLSession:(__unused NSURLSession *)session
    task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {

pragma clang diagnostic push

pragma clang diagnostic ignored "-Wgnu"

__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
NSData *data = nil;
if (self.mutableData) {
    data = [self.mutableData copy];
    //We no longer need the reference, so nil it out to gain back some memory.
    self.mutableData = nil;
}
if (self.downloadFileURL) {
    userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
    userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
    userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
    dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
        if (self.completionHandler) {
            self.completionHandler(task.response, responseObject, error);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
        });
    });
} else {
    dispatch_async(url_session_manager_processing_queue(), ^{
        NSError *serializationError = nil;
        responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
        if (self.downloadFileURL) {
            responseObject = self.downloadFileURL;
        }
        if (responseObject) {
            userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
        }
        if (serializationError) {
            userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
        }
        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, serializationError);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    });
}

pragma clang diagnostic pop

}
以上代码中 data = [self.mutableData copy] 可知网络数据流被copy到了 data之中,关键代码:

responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]
网络数据被解析成了我们最终获取到的数据。self.completionHandler一执行如下代码块:

1
2
3
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
就回到了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
28
29
30
31
32
33
34
35
36

  • (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
    URLString:(NSString *)URLString
    parameters:(id)parameters
    success:(void (^)(NSURLSessionDataTask *, id))success
    failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
    {
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
    if (failure) {

pragma clang diagnostic push

pragma clang diagnostic ignored "-Wgnu"

        dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
            failure(nil, serializationError);
        });

pragma clang diagnostic pop

    }
    return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
    if (error) {
        if (failure) {
            failure(dataTask, error);
        }
    } else {
        if (success) {
            success(dataTask, responseObject);
        }
    }
}];
return dataTask;

}
这block就会被调用:

1
2
3
4
5
6
7
8
9
10
11
12
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
这里的success和 failure 就是我们经常看见的回调方法。

你可能感兴趣的:(AFNetWorking 深度理解)