概述
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];
响应数据:
略
这是比较简单的使用场景,但是如果遇到稍微复杂一些的需求,比如断点下载,那代码就不止这么多了,你需要实现NSURLSessionDelegate
、NSURLSessionDataDelegate
、NSURLSessionTaskDelegate
中相应的一些代理方法去实现这些逻辑,稍微有些麻烦,而且场景多的话,代码不容易管理会显得混乱,所幸有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 block
和failure block
就可以看做是对NSURLSessionDelegate
的一些代理方法的封装,我们会在接下来的内容中继续深入讲解。
AFNetworking的核心类
- AFHTTPSessionManager
- AFURLSessionManager
- AFHTTPRequestSerializer
- AFHTTPResponseSerializer
- AFSecurityPolicy
- AFNetworkReachabilityManager
本篇重点讲的就是前两个类。
AFNetworking是如何封装众多代理方法的?
AFNetworking是如何封装众多代理方法的?知道了这个问题的答案基本就知道了AFNetworking的工作流程,所以解答这两个问题就要剖析AFHTTPSessionManager
和AFURLSessionManager
这两个核心类。
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
类,也就是说AFURLSessionManager
是AFHTTPSessionManager
的父类。
到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
(也很重要)
当我们调用AFHTTPSessionManager
的GET
等方法时,顺着函数调用栈我们最终可以定位到,整个操作的最终目的是获取并返回一个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
之外,还有上传文件及下载文件所用的NSURLSessionUploadTask
和NSURLSessionDownloadTask
,这些函数内部所做的事都是一样的,我们挑一个函数来讲一下就可以了,以第一个函数为例,代码如下:
- (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
则是task
的taskIdentifier
。
(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
进行cancle
,resume
和suspend
等操作,NSProgress
和NSURLSessionTask
的操作很好的关联在了一起。
(2)使用KVO
对task
进行键值监听,使用KVO
对downloadProgress
和uploadProgress
进行键值监听。
监听函数实现如下:
- (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);
}
}
}
在这个函数中,会实时更新downloadProgress
和uploadProgress
的进度,并将这两个NSProgress
对象通过block
传递出去。
我们可以看到,downloadProgressBlock
,uploadProgressBlock
和completionHandler
这些回调,包括uploadProgress
和downloadProgress
这些对象,都属于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
对象调用completionHandler
、uploadProgressBlock
、downloadProgressBlock
等block回调,然后把这个task
删除。
(3)调用AFN自身定义的block回调函数
在AFURLSessionManagerTaskDelegate
对象中,如何处理任务?
AFURLSessionManagerTaskDelegate
对象也实现了NSURLSessionDataTask
的URLSession: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的核心骨架。
网友评论