AFN详解

作者: rayChow | 来源:发表于2016-12-06 13:52 被阅读1566次

    在iOS开发中AFNetworking占据了不小的分量,因此,对AFN进行详细的剖析。先看下AFN的目录结构:

    Snip20161205_1.png
    网络请求有两种方式。一种就是用AFHTTPRequestOperationManager,另一种就是AFHTTPSessionManager。那么这两种有什么区别呢?

    AFNetworking最初的版本使用的是AFHTTPRequestOperationManager,以自己定义的NSOperation的封装实现的。AFHTTPSessionManager是2.0以后才引进的。

    AFHTTPSessionManager继承自AFURLSessionManager,而AFURLSessionManager主要是使用系统提供的NSURLSessionManager和NSURLSessionTask进行网络操作的。这两个类是iOS7以后才出现的,所以,如果想适配到iOS6,那么就要使用AFHTTPRequestOperationManager进行网络请求。

    下面就分两部分对AFN网络请求进行分析:

    AFHTTPRequestOperationManager的网络请求原理:

    AFHTTPRequestOperationManager的init方法:

    - (instancetype)initWithBaseURL:(NSURL *)url {
        if (!(self = [super init])) {
            return nil;
        }
        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;
    }
    

    其中,默认的请求方式和解析方式被设置了默认值:

        self.requestSerializer = [AFHTTPRequestSerializer serializer];
        self.responseSerializer = [AFJSONResponseSerializer serializer];
    

    当然,用户可以修改这两个参数,指定自己的请求方式和解析方式。下面以GET请求为例来说。

    当用户发起一个GET请求时,下面的方法会被调用:

    - (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 <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>
    

    我们知道当一个operation任务被启动的时候start方法就会被调用:

    - (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任务被正常启动的时候,下面的方法会被调用:

    [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 方法中的:

    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.connectionself.outputStream周期性任务被绑定在当期的runloopself.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中的代理方法:

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

    被调用,通过以上代码中的:

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

    网络数据流被写入缓存。数据被写入缓存完成后,代理方法:

    - (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]; 看看它里面的实现:

    - (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的操作,如下代码:

    - (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方法被回调:

    - (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];
    }
    

    关键看这句代码:

    dispatch_group_async(group, queue, ^{
                    block();
                });
    

    block()一调用就调用到了AFHTTPRequestOperation的方法:

    #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的实现:

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

    这句代码:

    self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
    

    stream中的数据解析成了我们想要数据比如````json、xml、plist等等。然后AFHTTPRequestOperation方法setCompletionBlockWithSuccess中代码success(self, responseObject)一回调。好了,现在就不用说了,我们通常就是在这个success block```做我们自己的处理的。

    AFHTTPSessionManager的网络请求原理:

    苹果对NSURLSeesionDataTask做了封装,类似于AFURLConnectOperation这样的封装已经不见了,但原理跟AFURLConnectionOperation差不多。

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

    - (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]里面的实现是这样的:

    - (void)URLSession:(__unused NSURLSession *)session
              dataTask:(__unused NSURLSessionDataTask *)dataTask
        didReceiveData:(NSData *)data
    {
        [self.mutableData appendData:data];
    }
    

    这样网络数据就被写入了self.mutableData
    当数据获取完成之后URLSession:task:didCompleteWithError:方法就会被调用:

    - (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]方法中的实现:

    - (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一执行如下代码块:

    if (self.completionHandler) {
        self.completionHandler(task.response, responseObject, serializationError);    
    }
    

    就回到了AFHTTPSessionManager的方法:

    - (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就会被调用:

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

    这里的successfailure就是我们经常看见的回调方法。

    相关文章

      网友评论

          本文标题:AFN详解

          本文链接:https://www.haomeiwen.com/subject/etzkmttx.html