原理篇iOS Developer网络请求

AFNetworking核心源码解析

2017-06-28  本文已影响400人  fou7

概述

AFNetworking 实际上是对 NSURLSession高度封装,并且AFNetworking为我们提供了一些更加简单易用的方法,方便我们在开发中发送网络请求后获取到相应的响应数据,并在此基础上构建项目的网络组件。

使用NSURLSession进行网络请求

代码:

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"http://www.weather.com.cn/weather/101010100.shtml"]];
    
NSURLSession *session = [NSURLSession sharedSession];
    
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", dataStr);
}];
    
[task resume];

响应数据:

这是比较简单的使用场景,但是如果遇到稍微复杂一些的需求,比如断点下载,那代码就不止这么多了,你需要实现NSURLSessionDelegateNSURLSessionDataDelegateNSURLSessionTaskDelegate中相应的一些代理方法去实现这些逻辑,稍微有些麻烦,而且场景多的话,代码不容易管理会显得混乱,所幸有AFNetworking。

使用AFNetworking进行网络请求

代码:

AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[[NSURL alloc] initWithString:@"hostname"]];

[manager GET:@"relative_url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"%@" ,responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@", error);
}];

从上面的代码我们可以看出,一个网络请求发出去之后,会有两个block回调,一种是响应成功的success block回调,一种是响应失败的failure block回调,而success blockfailure block就可以看做是对NSURLSessionDelegate的一些代理方法的封装,我们会在接下来的内容中继续深入讲解。

AFNetworking的核心类

本篇重点讲的就是前两个类。

AFNetworking是如何封装众多代理方法的?

AFNetworking是如何封装众多代理方法的?知道了这个问题的答案基本就知道了AFNetworking的工作流程,所以解答这两个问题就要剖析AFHTTPSessionManagerAFURLSessionManager这两个核心类。

AFHTTPSessionManager

当我们使用AFHTTPSessionManager时,第一件要做的事肯定是初始化。我们进入AFHTTPSessionManager类的实现文件中,找到初始化方法如下:

+ (instancetype)manager {
    return [[[self class] alloc] initWithBaseURL:nil];
}

- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}

- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    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];

    return self;
}

重点看最下面的那个initWithBaseURL : sessionConfiguration方法。

在这个方法中,有一段代码是十分重要的,self = [super initWithSessionConfiguration:configuration];,点进去,直接来到了AFURLSessionManager类,也就是说AFURLSessionManagerAFHTTPSessionManager的父类。

AFHTTPSessionManager.h文件中一看,果不其然。

那就从AFURLSessionManager继续看。

AFURLSessionManager

还是先找到初始化方法,如下:

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;

    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 3;

    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

    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    [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)初始化会话配置(session configuration),默认为defaultSessionConfiguration
(2)初始化队列,设置队列的最大并发数
(3)初始化会话(session),并将session的代理对象设置为self(也就是当前AFURLSessionManager对象),并将代理队列设置为(2)中创建的队列。
(4)初始化响应序列化
(5)初始化安全认证
(6)初始化网络状态监控
(7)初始化保存NSURLSessionDataTask的字典(很重要)
(8)初始化线程锁(很重要)
(9)最后一大坨代码是为已经存在的task设置delegate(也很重要)

当我们调用AFHTTPSessionManagerGET等方法时,顺着函数调用栈我们最终可以定位到,整个操作的最终目的是获取并返回一个NSURLSessionDataTask对象。

NSURLSessionDataTask对象的创建和返回时依靠如下几个方法:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
}

- (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;
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

#pragma mark -

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
   具体函数实现略
}

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(NSData *)bodyData
                                         progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
   具体函数实现略
}

- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                        completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    具体函数实现略
}

#pragma mark -

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                          destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
    具体函数实现略
}

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                             destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
    具体函数实现略
}

可以看出除了NSURLSessionDataTask之外,还有上传文件及下载文件所用的NSURLSessionUploadTaskNSURLSessionDownloadTask,这些函数内部所做的事都是一样的,我们挑一个函数来讲一下就可以了,以第一个函数为例,代码如下:

- (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;
    url_session_manager_create_task_safely(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

在这个函数中,做了这几件事:
(1)通过调用NSURLSession dataTaskWithRequest:方法传入的NSURLRequest对象,获取NSURLSessionDataTask对象。
(2)调用addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:函数,给刚才创建的NSURLSessionDataTask对象设置代理(准确点说应该是将AFURLSessionManagerTaskDelegate对象与NSURLSessionTask对象相关联,并没有设置代理)。
(3)返回这个NSURLSessionDataTask对象。

再来看addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:函数:

- (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
{
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

在这个函数中,它做了几件事:
(1)创建一个AFURLSessionManagerTaskDelegate对象。
(2)设置AFURLSessionManagerTaskDelegate对象的manager为当前对象
(3)设置AFURLSessionManagerTaskDelegate对象的completionHandler(完成回调事件)
(4)设置AFURLSessionManagerTaskDelegate对象的uploadProgressBlock(上传进度回调事件)
(5)设置AFURLSessionManagerTaskDelegate对象的downloadProgressBlock(下载进度回调事件)
(6)设置AFURLSessionManagerTaskDelegate对象的taskDescription
(7)调用setDelegate:forTask:方法

注意:

这个AFURLSessionManagerTaskDelegate对象非常重要!我们可以看到各种回调实际上都封装在了AFURLSessionManagerTaskDelegate对象中,到时取的时候自然也是从AFURLSessionManagerTaskDelegate对象中去取。

来看setDelegate:forTask:的函数实现,如下:

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

在这个函数中做了这几件事(这里特别重要):
(1)首先,这里使用了在初始化方法中创建的锁,进而保证在不同线程中使用 mutableTaskDelegatesKeyedByTaskIdentifier时不出现线程竞争的问题。
(2)mutableTaskDelegatesKeyedByTaskIdentifier是在初始化方法中创建的字典,它的用处是用来存储并管理每一个NSURLSessionTask对象,字典的value就是NSURLSessionTask对象,key则是tasktaskIdentifier
(3)然后执行setupProgressForTask:函数
(4)最后执行addNotificationObserverForTask:函数

setupProgressForTask:函数实现:

- (void)setupProgressForTask:(NSURLSessionTask *)task {
    __weak __typeof__(task) weakTask = task;

    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
    [self.uploadProgress setCancellable:YES];
    [self.uploadProgress setCancellationHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask cancel];
    }];
    [self.uploadProgress setPausable:YES];
    [self.uploadProgress setPausingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask suspend];
    }];
    if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
        [self.uploadProgress setResumingHandler:^{
            __typeof__(weakTask) strongTask = weakTask;
            [strongTask resume];
        }];
    }

    [self.downloadProgress setCancellable:YES];
    [self.downloadProgress setCancellationHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask cancel];
    }];
    [self.downloadProgress setPausable:YES];
    [self.downloadProgress setPausingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask suspend];
    }];

    if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
        [self.downloadProgress setResumingHandler:^{
            __typeof__(weakTask) strongTask = weakTask;
            [strongTask resume];
        }];
    }

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [self.downloadProgress addObserver:self
                            forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                               options:NSKeyValueObservingOptionNew
                               context:NULL];
    [self.uploadProgress addObserver:self
                          forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                             options:NSKeyValueObservingOptionNew
                             context:NULL];
}

在这个函数实现中,虽然代码看起来很多,但主要就做了两件事:
(1)设置在上传或下载文件时进度状态改变的回调,当进度状态改变的同时,我们可以对task进行cancleresumesuspend等操作,NSProgressNSURLSessionTask的操作很好的关联在了一起。
(2)使用KVOtask进行键值监听,使用KVOdownloadProgressuploadProgress进行键值监听。

监听函数实现如下:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
            self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
            self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
            self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
            self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        }
    }
    else if ([object isEqual:self.downloadProgress]) {
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }
    else if ([object isEqual:self.uploadProgress]) {
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

在这个函数中,会实时更新downloadProgressuploadProgress的进度,并将这两个NSProgress对象通过block传递出去。

我们可以看到,downloadProgressBlockuploadProgressBlockcompletionHandler这些回调,包括uploadProgressdownloadProgress这些对象,都属于AFURLSessionManagerTaskDelegate对象!

AFNetworking将这些重要的回调和属性最后又封装到了AFURLSessionManagerTaskDelegate对象中。

以上,就是创建并返回一个NSURLSessionDataTask对象的流程。

真正的封装,AFN处理NSURLSession的回调函数

刚才创建的每个NSURLSessionDataTask对象都是一个任务,每个任务完成后都会触发AFURLSessionManager对象的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);
    }
}

函数作用如下:
(1)通过delegateForTask:函数取出AFURLSessionManagerTaskDelegate对象。
(2)如果AFURLSessionManagerTaskDelegate对象存在,就把任务交给AFURLSessionManagerTaskDelegate对象来完成,任务完成后,由AFURLSessionManagerTaskDelegate对象调用completionHandleruploadProgressBlockdownloadProgressBlock等block回调,然后把这个task删除。
(3)调用AFN自身定义的block回调函数

AFURLSessionManagerTaskDelegate对象中,如何处理任务?
AFURLSessionManagerTaskDelegate对象也实现了NSURLSessionDataTaskURLSession:task:didCompleteWithError:代理方法,实现如下:

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    __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;
    }

    // 如果task出错了,处理error信息
    // 所以对应的观察者在处理error的时候,比如可以先判断userInfo[AFNetworkingTaskDidCompleteErrorKey]是否有值,有值的话,就说明是要处理error
    if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;

        // dispatch_group_async可以实现监听一组任务是否完成,完成后通知执行其他的操作
        // 这里用group方式来运行task完成方法,表示当前所有的task任务完成,才会通知执行其他操作
        // 如果没有实现自定义的completionGroup,就使用AFNetworking提供的私有的dispatch_group_t(url_session_manager_completion_group())
        //如果没有实现自定义的completionQueue,就使用系统提供的主队列函数(dispatch_get_main_queue)
        //最后实际上就是把在子线程得到响应数据传到了主线程中
        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);
            }

            //操作完成后,post一个通知,表示操作全部完成了
            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];
                });
            });
        });
    }
}

以上就是AFNetworking的核心骨架。

上一篇下一篇

猜你喜欢

热点阅读