一丧靡、概述
從上圖可以發(fā)現(xiàn),AFNetworking框架的結(jié)構(gòu)比較清晰簡(jiǎn)潔钞支,主要范圍5個(gè)部分:
- 網(wǎng)絡(luò)通信模塊:URLSession
- 網(wǎng)絡(luò)狀態(tài)監(jiān)聽模塊:Reachability
- 網(wǎng)絡(luò)通信安全模塊:Security
- 網(wǎng)絡(luò)通信序列化模塊:Serialization
- 對(duì)UIKit框架擴(kuò)展部分:UIKit(以Catagory形式添加特性)
AFNetworking的核心是AFURLSessionManager類绅作,這個(gè)類基于NSURLSession营曼,圍繞NSURLSession做了一系列的封裝,其余的四個(gè)類都是該類用于網(wǎng)絡(luò)通信的一個(gè)屬性或?qū)σ延蠻IKit的一個(gè)擴(kuò)展工具包尿贫。
其中AFHTTPSessionManager類是繼承于AFURLSessionManager的电媳,我們使用AFNetworking時(shí),都是用AFHTTPSessionManager庆亡,但它本身沒有做實(shí)事的匾乓,只是做了一些簡(jiǎn)單的封裝,把請(qǐng)求邏輯分發(fā)給父類AFURLSessionManager又谋。
二拼缝、AFNetworking使用
例子:
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"application/json", @"text/json" ,@"text/javascript", nil];
session.responseSerializer = [AFHTTPResponseSerializer serializer];
[session GET:@"https://www.baidu.com"
parameters:nil
headers:nil
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"請(qǐng)求成功");
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"請(qǐng)求失敗");
}];
三、AFNetworking使用的代碼分析
3.1 [AFHTTPSessionManager manager]
AFHTTPSessionManager is a subclass of AFURLSessionManager with convenience methods for making HTTP requests. When a base URL is provided, requests made with the GET/POST/ et al. convenience methods can be made with relative paths.
AFHTTPSessionManager manage的實(shí)現(xiàn)
+ (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;
}
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
進(jìn)入到AFURLSessionManager的- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration方法中分析
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
// 1. 設(shè)置全局的網(wǎng)絡(luò)行為策略的配置
self.sessionConfiguration = configuration;
// 2. 設(shè)置請(qǐng)求的隊(duì)列彰亥,默認(rèn)最大的并發(fā)數(shù)為1
self.operationQueue = [[NSOperationQueue alloc] init];
// (1)這里的并發(fā)數(shù)指的是回調(diào)代理的線程并發(fā)數(shù)咧七,而不是請(qǐng)求網(wǎng)絡(luò)的線程并發(fā)數(shù)。請(qǐng)求網(wǎng)絡(luò)是由NSURLSession來做的任斋,它內(nèi)部維護(hù)了一個(gè)線程池用來做網(wǎng)絡(luò)請(qǐng)求猪叙。NSURLSession調(diào)度線程是基于底層的CFSocket去發(fā)送請(qǐng)求和接收數(shù)據(jù),這些線程是并發(fā)的。
// (2)AF2.x所有回調(diào)是在一條線程穴翩,這條線程是AF的常駐線程犬第,而這一條線程正式AF調(diào)度request的思想精髓所在。所以線程數(shù)設(shè)置為1的第一個(gè)目的是和之前版本保持一致芒帕;
// (3)因?yàn)楦硐嚓P(guān)的一些操作AF都使用了NSLock歉嗓,所以Queue的并發(fā)數(shù)設(shè)置為n,也會(huì)因?yàn)槎嗑€程回調(diào)背蟆、鎖的等待鉴分,導(dǎo)致提升的程序速度并不明顯,反而多task回調(diào)導(dǎo)致的多線程并發(fā)带膀,平白浪費(fèi)了部分性能志珍。至少回調(diào)的事件,是不需要多線程并發(fā)的垛叨,回調(diào)沒有了NSLock的等待事件伦糯,所以對(duì)事件并沒有多大影響。
self.operationQueue.maxConcurrentOperationCount = 1;
// 3. 設(shè)置網(wǎng)絡(luò)請(qǐng)求響應(yīng)的數(shù)據(jù)解析實(shí)例
self.responseSerializer = [AFJSONResponseSerializer serializer];
// 4. 設(shè)置網(wǎng)絡(luò)請(qǐng)求安全策略實(shí)例(后續(xù)說明該實(shí)例)
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
// 5. 初始化全局的網(wǎng)絡(luò)狀態(tài)監(jiān)聽的實(shí)例
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
// 6. 將taskID與其Delegate綁定嗽元,實(shí)現(xiàn)解耦(后續(xù)進(jìn)行分析)
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
// 7. self.session采用懶加載敛纲,根據(jù)configuration,operationQueue初始化全局的NSURLSession
[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;
}
- (NSURLSession *)session {
@synchronized (self) {
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
}
}
return _session;
}
3.2 NSURLSessionConfiguration 全局的網(wǎng)絡(luò)行為策略的配置
An NSURLSessionConfiguration object defines the behavior and policies to use when uploading and downloading data using an NSURLSession object. When uploading or downloading data, creating a configuration object is always the first step you must take. You use this object to configure the timeout values, caching policies, connection requirements, and other types of information that you intend to use with your NSURLSession object.
簡(jiǎn)單羅列以下兩點(diǎn):
1.NSURLSessionConfiguration可以控制網(wǎng)絡(luò)請(qǐng)求中的緩存策略剂癌,超時(shí)設(shè)置等淤翔;
2.如果需要改變網(wǎng)絡(luò)請(qǐng)求的行為策略,必須重新在更改NSURLSessionConfiguration后再創(chuàng)建一個(gè)新的NSURLSession佩谷。
3.3 AFHTTPSessionManager GET: parameters: headers: progress: success: failure: 方法
3.3.1 NSURLSessionTask
這里引入了一個(gè)新的類:NSURLSessionDataTask旁壮。NSURLSessionDataTask繼承了NSURLSessionTask。** NSURLSessionTask**的官方說明:
The NSURLSessionTask class is the base class for tasks in a URL session. Tasks are always part of a session; you create a task by calling one of the task creation methods on an NSURLSession object. The method you call determines the type of task.
URL sessions provide three types of tasks: data tasks, upload tasks, and download tasks. These tasks are instances of the NSURLSessionDataTask, NSURLSessionUploadTask, NSURLSessionDownloadTask, NSURLSessionStreamTask subclasses of NSURLSessionTask, respectively.
簡(jiǎn)單羅列以下兩點(diǎn):
1.NSURLSessionTask是官方提供的幾種網(wǎng)絡(luò)任務(wù)類的基類谐檀;
2.官方提供了三種任務(wù)處理的子類:簡(jiǎn)單數(shù)據(jù)處理任務(wù)類寡具、上傳任務(wù)類和下載任務(wù)類。
3.3.2 AFHTTPSessionManager dataTaskWithHTTPMethod:...方法實(shí)現(xiàn)與分析
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
headers:(NSDictionary<NSString *,NSString *> *)headers
uploadProgress:(void (^)(NSProgress * _Nonnull))uploadProgress
downloadProgress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {
NSError *serializationError = nil;
// 1.通過全局配置的requestSerializer初始化一個(gè)請(qǐng)求的實(shí)例
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
for (NSString *headerField in headers.keyEnumerator) {
[request setValue:headers[headerField] forKey:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
// 2.根據(jù)請(qǐng)求的實(shí)例再初始化一個(gè)task的實(shí)例
__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;
}
3.3.3 [AFURLSessionManager addDelegateForDataTask:...]方法稚补,用于task與delegate的綁定
// 1. 根據(jù)請(qǐng)求信息初始化一個(gè)task實(shí)例
- (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 {
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
- (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
{
// 2.初始化一個(gè)任務(wù)的代理
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
// 此處賦值了請(qǐng)求完成的回調(diào)童叠,后續(xù)會(huì)用到
delegate.completionHandler = completionHandler;
// 3.利用全局的字典存儲(chǔ)綁定信息,key為taskID课幕,value為代理的實(shí)例厦坛。
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
// 1.綁定taskID與代理self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 2.使用KVO對(duì)一些方法監(jiān)聽,返回上傳或下載的進(jìn)度
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
3.3.4 NSURLSessionTaskDelegate協(xié)議中的URLSession:task:didCompleteWithError:方法
NSURLSessionTaskDelegate協(xié)議包含NSURLSessionDelegate協(xié)議
當(dāng)請(qǐng)求收到了響應(yīng)后乍惊,會(huì)觸發(fā)- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error;回調(diào)(AFURLSessionManager的session屬性懶加載時(shí)杜秸,設(shè)置了delegate為self,會(huì)觸發(fā)該代理的方法)润绎,以下是方法中的具體處理撬碟。
// AFURLSessionManager.m中NSURLSessionTaskDelegate方法的實(shí)現(xiàn)诞挨,該方法由系統(tǒng)自動(dòng)觸發(fā)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// 1.根據(jù)task獲取綁定的代理實(shí)例
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
// 2.統(tǒng)一處理,調(diào)用AFURLSessionManagerTaskDelegate的同名方法呢蛤。
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
// AFURLSessionManagerTaskDelegate.m中NSURLSessionTaskDelegate方法的實(shí)現(xiàn)惶傻,該方法在AFURLSessionManager中通過delegate調(diào)用。
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
error = objc_getAssociatedObject(task, AuthenticationChallengeErrorKey) ?: error;
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
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 AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS
if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) {
if (self.sessionTaskMetrics) {
userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics;
}
}
#endif
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
// 1.iOS網(wǎng)絡(luò)框架返回的錯(cuò)誤信息處理
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 {
// 2.請(qǐng)求成功后需要用響應(yīng)的數(shù)據(jù)解析類的responseSerializer實(shí)例處理返回的數(shù)據(jù)
// 數(shù)據(jù)通過NSURLSessionDataDelegate協(xié)議的- (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data方法返回
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(), ^{
// 3.綁定task與處理的數(shù)據(jù)代理時(shí)其障,傳入代理的完成的回調(diào)
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}
參考來源:
https://toutiao.io/posts/dibcw7/preview
https://www.cnblogs.com/ederwin/articles/10592839.html