AFNetworking 是一个 iOS 平台的网络框架,简洁易懂,所以在实际项目开发中用的极多,AFNetworking 本质上还是基于苹果自身的网络通信机制,这里就剖析一下其内部代码。
框架概述
将 AFNetworking 代码下载过来,目录树如下:
total 240
drwxr-xr-x@ 15 chasontang staff 510B 4 1 01:28 AFNetworking
-rw-r--r--@ 1 chasontang staff 2.5K 4 1 01:28 AFNetworking.podspec
drwxr-xr-x@ 5 chasontang staff 170B 4 27 17:03 AFNetworking.xcodeproj
drwxr-xr-x 4 chasontang staff 136B 4 27 17:03 AFNetworking.xcworkspace
-rw-r--r--@ 1 chasontang staff 87K 4 1 01:28 CHANGELOG.md
-rw-r--r--@ 1 chasontang staff 4.1K 4 1 01:28 CONTRIBUTING.md
drwxr-xr-x@ 19 chasontang staff 646B 4 27 17:04 Example
drwxr-xr-x@ 5 chasontang staff 170B 4 1 01:28 Framework
-rw-r--r--@ 1 chasontang staff 1.1K 4 1 01:28 LICENSE
-rw-r--r--@ 1 chasontang staff 14K 4 1 01:28 README.md
drwxr-xr-x@ 7 chasontang staff 238B 4 27 17:10 Tests
drwxr-xr-x@ 22 chasontang staff 748B 4 1 01:28 UIKit+AFNetworking
drwxr-xr-x@ 17 chasontang staff 578B 4 1 01:28 fastlane
但是本质上只有 AFNetworking 文件夹是实际的代码,而其他都是样例工程、测试用例、使用工具类等。AFNetworking 文件夹下只有 6 个类文件和 1 个汇总头文件,总共大约 5000 行代码。
AFNetworking.h - header file
AFNetworkReachabilityManager - class
AFSecurityPolicy - class
AFURLRequestSerialization - class
AFURLResponseSerialization - class
AFURLSessionManager - class
AFHTTPSessionManager - class
不过需要注意的是,看起来只存 6 个类文件,但是实际上一个类文件中包含了多个存在继承关系的类,这点确实是瑕疵,容易造成误解。
苹果自身提供的网络通信框架也被称之为 URL loading system
,主要使用 NSURLSession
、NSURLConnection
两个类作为通信管理类,其中,NSURLSession
只能进行异步通信,而且可以进行后台网络通信,只能用于 iOS 7 及以后版本。而 NSURLConnection
既可以异步也可以同步通信。AFNetworking 则是基于这套机制封装的,并且是继承 NSURLSession
类。
注意:本文所指 AFNetworking 是指 3.x 版本,NSURLConnectionOperation 支持已经被移除了,框架要求最低为 iOS 7 版本。
框架类继承如下:
NSURLSession
AFURLSessionManager
AFHTTPSessionManager
AFURLRequestSerialization
AFHTTPRequestSerializer
AFJSONRequestSerializer
AFPropertyListRequestSerializer
AFURLResponseSerialization
AFHTTPResponseSerializer
AFJSONResponseSerializer
AFXMLParserResponseSerializer
AFPropertyListResponseSerializer
AFImageResponseSerializer
AFCompoundResponseSerializer
AFSecurityPolicy
AFNetworkReachabilityManager
源代码剖析
AFNetworking.h
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#ifndef _AFNETWORKING_
#define _AFNETWORKING_
#import "AFURLRequestSerialization.h"
#import "AFURLResponseSerialization.h"
#import "AFSecurityPolicy.h"
#if !TARGET_OS_WATCH
#import "AFNetworkReachabilityManager.h"
#endif
#import "AFURLSessionManager.h"
#import "AFHTTPSessionManager.h"
#endif /* _AFNETWORKING_ */
很常规的思路,导入所需头文件,宏定义用于防止头文件重复包含,苹果手表平台不导入 AFNetworkReachabilityManager 头文件。
AFHTTPSessionManager
首先这个类是继承自 AFURLSessionManager,实现了 <NSSecureCoding, NSCopying>
协议,而 AFURLSessionManager 则是继承自 NSObject,并且实现了 <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
。
对于大多数开发来说,都是使用 AFHTTPSessionManager 作为网络请求中心。其中有两个重要成员变量:requestSerializer、responseSerializer 分别是请求序列化器和回应序列化器,应该不用多说,从字面上也能猜出其内容。然后就分别是以下方法:
+ (instancetype)manager;
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
一个工厂方法,然后就是 GET、HEAD、POST、PUT、PATCH 和 DELETE 方法。标记为 DEPRECATED_ATTRIBUTE
的则是弃用方法,一些方法带有 progressBlock,便于计算加载过程。工厂方法 + (instancetype)manager
实际上还是创建了一个 baseURL 为 nil 的实例,所以应当避免调用工厂方法,而是手动创建对象。而所有初始化方法都会调用 initWithBaseURL:sessionConfiguration:
方法,以下是初始化方法代码:
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;
主要就是整理了 baseURL,然后创建了 AFHTTPRequestSerializer 作为请求序列化器,AFJSONResponseSerializer 作为相应序列化器,也就是默认情况下返回 JSON。
再来看请求方法,很容易就能看出其流程为:变体请求方法 -> 基请求方法 -> dataTaskWithHTTPMethod:URLString:parameters:uploadProgress:downloadProgress:success:failure:
,就是返回了类型为 NSURLSessionDataTask 的对象,然后调用 [dataTask resume]
执行请求。
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
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
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
注意,除了一个 POST 方法的变体方法以外,这是所有 HTTP 请求方法的公共出口,主要就是创建一个 NSURLSessionDataTask 对象。POST 方法有一个变体方法是使用 FORMDATA 的形式发起 HTTP 请求,所以无法归纳到公共抽象代码内,因此独立实现了其方法,但是实际上也是差不多的,这里就不多讲了。
首先就是创建 NSMutableURLRequest 对象,如果出错,则使用 GCD 调用 failure 回调函数。否则其调用父类的 dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
方法创建 NSURLSessionDataTask 对象。
AFNetworkReachabilityManager
这个类用于检查网络联网状态,实际上是模仿苹果官方示例代码 reachability,这里就不提了,各位自行观看代码实现。