1. 程式人生 > >AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h

AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h

AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h

AFURLSessionManager.h 介紹

根據開頭註釋中的介紹,大體意思就是,這個類是管理整個網路請求的生命週期,繪畫排程,代理方法實現,請求傳送及其回掉處理的類,可以說她是AFN的核心。

屬性解析

@property (readonly, nonatomic, strong) NSURLSession *session;

回話物件

@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

委託執行回撥操作佇列,也就是說,這個佇列中處理的都是回掉代理回撥的操作

@property (nonatomic, strong
) id <AFURLResponseSerialization> responseSerializer;

響應序列化

- 1.根據註釋:它的作用就是方便對伺服器的響應資料進行序列化的操作。

- 2.預設是AFJSONResponseSerializer 並且這個屬性在使用的時候不能為nil

- 3.它必須是遵循AFURLResponseSerialization協議的物件,我們可以在檔案中看到 AFURLResponseSerialization.hAFHTTPResponseSerializer 的定義是:
@interface AFHTTPResponseSerializer : NSObject <AFURLResponseSerialization>
所以,這個物件我們可以在後邊拜讀AFURLResponseSerialization檔案的時候詳細探究

Getting Session Tasks (獲取不同task介面,不細說)

///----------------------------
/// @name Getting Session Tasks
///----------------------------

/**
 The data, upload, and download tasks currently run by the managed session.
 */
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

/**
 The data tasks currently run by the managed session.
 */
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

/**
 The upload tasks currently run by the managed session.
 */
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

/**
 The download tasks currently run by the managed session.
 */
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

Managing Callback Queues

@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

執行完成時使用的回撥佇列,可以為空,為空時使用主佇列

@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

執行完成時使用的Group,可以為空,為空時使用私有的一個Group

@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;

在iOS7中 在後臺建立 upload task 時可能失敗,為nil,如果把這個屬性設定為YES ,AFNetWorking會遵循Apple的建議去重新建立。

Initialization

- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

- 1.指定的初始化方法
- 2.需要一個NSURLSessionConfiguration
- 3.NS_DESIGNATED_INITIALIZER 巨集代表初始化只能用這一個,這是一個指定的初始化方法

- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

是否取消這個管理類下的Seesion中 pending 的 task


Running Data Tasks

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler 
DEPRECATED_ATTRIBUTE;

- 1.使用DataTask,執行一個HTTP請求
- 2.返回系統預設的response
- 3.返回根據serializer序列化後的responseObject
- 4.返回error
- 5.DEPRECATED_ATTRIBUTE 標註為不建議使用,即將廢棄


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

- 1.同上一個方法一樣,使用Data Task 發起一個HTTP請求
- 2.多了uploadProgressBlock,downloadProgressBlock 回撥上傳和下載進度
- 3.注意,這兩個progressBlock並不是在主執行緒回撥的,而是在session所線上程,如果需要UI操作,請放到主執行緒中
- 4.completionHandler同上
- 5.這樣看來,這個方法可以說是上一個方法的替代 (悄悄的改調自己封裝的內容。。。)


Running Upload Tasks

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError  * _Nullable error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(nullable NSData *)bodyData
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

- 1.以上三個方法分別是本地檔案,Http Body,標準檔案流 上傳方法
- 2.HTTP傳輸過程中雖然都是以二進位制的形式在傳輸資料,但是對於發起方可能存在需要傳輸的資料本身的差異性,比如它是一個本地檔案,一個字串,甚至直接就是流。
- 3.所以,對於著幾個方法我們也大可不必糾結為什麼這麼多形式,暫且把它們理解為對不同型別物件上傳的友好封裝(可能事實也是這樣,需要我們看.m檔案探究)
- 4.第一個方法中對attemptsToRecreateUploadTasksForBackgroundSessions屬性做了警告,不知道下邊兩個方法是否需要,根據該屬性的說明,應該是都需要,具體需要實踐


Running Download Tasks

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                          destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

- 1.使用Download Task下載
- 2.可以設定對應的檔案下載後的儲存路徑destination
- 3.但是,在destination在後臺下載的時候是不管用的,因為在後臺時,這個方法中的block是不能夠回撥的,需要使用-setDownloadTaskDidFinishDownloadingBlock:指明在後臺下載時的檔案儲存路徑

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                             destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

- 1.簡單理解為斷點續傳/繼續下載
- 2.resumeData 已經下載完成的資料


Getting Progress for Tasks

- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;

獲取當前session task的上傳進度

- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

獲取當前session task的下載進度


Setting Session Delegate Callbacks

以下方法中設定的block都會在對應的NSURLSessionDelegate方法中執行

as handled by the NSURLSessionDelegate method URLSession:didBecomeInvalidWithError:

- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;

- 1.設定session失效時的回撥block
- 2.它的呼叫是根據NSURLSessionDelegateURLSession:didBecomeInvalidWithError:呼叫


as handled by the NSURLSessionDelegate method URLSession:didReceiveChallenge:completionHandler:

- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

- 1.設定收到認證挑戰時的方法的方法
- 2.在這個方法中我們可以收到響應的NSURLCredential *credentialNSURLAuthenticationChallenge *challenge
- 3.我們可以在2中的兩個引數中獲取到響應者的host port credential等資訊,這樣我們就可以判別響應者是否是我們的真實的伺服器,或者是否滿足我們特定的需求,進而做安全策略,防止postman/charles等抓包工具抓包,中間人劫持等都有效果
- 4.NSURLSessionDelegate中的URLSession:didReceiveChallenge:completionHandler:回撥時會呼叫這裡設定的block



Setting Task Delegate Callbacks

以下方法中設定的block都會在對應的NSURLSessionTaskDelegate方法中執行

as handled by the NSURLSessionTaskDelegate method URLSession:task:needNewBodyStream:

- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;

當對於一個基於資料流上傳主體的任務認證失敗的時候,任務不能安全的倒回並且重使用之前的資料流。NSRLSession 物件會呼叫代理的 URLSession:task:needNewBodyStream: 方法來獲取一個能夠為請求提供新的主體資料的新的 NSInputStream 物件


as handled by the NSURLSessionTaskDelegate method URLSession:willPerformHTTPRedirection:newRequest:completionHandler:

- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * _Nullable (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;

- 1.設定重定向request block
- 2.比如我們請求百度的時候,將請求重定向到qq


as handled by the NSURLSessionTaskDelegate method URLSession:task:didReceiveChallenge:completionHandler:

- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

- 1.設定身份驗證,自定義TLS,鏈驗證等處理方法的block
- 2.它和Setting Session Delegate Callbacks章節中的第二個方法是一樣的作用

兩個方法的區別:引用自這裡

對於會話層級別的授權請求 – NSURLAuthenticationMethodNTLM ,NSURLAuthenticationMethodNegotiate ,NSURLAuthenticationMethodClientCertificate 或者 NSURLAuthenticationMethodServerTrust – NSULRSession 物件會呼叫會話代理的 URLSession:didReceiveChallenge:completionHandler: 方法。如果 app 沒有實現該會話代理方法,那麼會代用任務代理的 URLSession:task:didReceiveChallenge:completionHandler: 方法來處理授權。

#

對於非會話層級別的請求 NSURLSession 物件呼叫會話代理的URLSession:task:didReceiveChallenge:completionHandler: 方法來處理,如果提供了會話的代理同時也需要去處理授權認證,那麼必須在任務級別也處理授權或者在任務中明確的呼叫每個會話來處理。會話代理方法 URLSession:didReceiveChallenge:completionHandler: 不會在非會話層級別的授權請求中被呼叫。



NSURLSessionTaskDelegate method URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;

- 1.定期獲取當前task中的upload任務已經發送和總共需要傳送的資料量
- 2.獲取當前上傳進度


NSURLSessionTaskDelegate method URLSession:task:didCompleteWithError:

- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;

task任務執行完畢的回撥


Setting Data Task Delegate Callbacks

以下方法中設定的block都會在對應的NSURLSessionDataDelegate方法中執行

as handled by the NSURLSessionDataDelegate method URLSession:dataTask:didReceiveResponse:completionHandler:

- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;

設定一個block,根據session,dataTask,response來決定task繼續下載、取消,轉成download task,轉成Stream task(NSURLSessionResponseDisposition)


as handled by the NSURLSessionDataDelegate method URLSession:dataTask:didBecomeDownloadTask:

- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;

如果上邊的方法中,block return NSURLSessionResponseBecomeDownload,則data task 會轉變成一個download task, 進而會呼叫該方法
如果該方法執行了,說明task已經成為了download task,以後的代理方法也不會再呼叫data task 的代理方法,而是走download task的代理方法


as handled by the NSURLSessionDataDelegate method URLSession:dataTask:didReceiveData:

- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;

在資料下載期間不定時的呼叫,返回每次下載回來的data,我們需要將這些data拼接,到最後獲取到完整的資料


as handled by the NSURLSessionDataDelegate method URLSession:dataTask:willCacheResponse:completionHandler:

- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;

根據返回的proposedResponse,dataTask,session來判定當前task下的response快取策略(TODO:NSURLCache NSCachedURLResponse)


as handled by the NSURLSessionDataDelegate method URLSessionDidFinishEventsForBackgroundURLSession:

- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block AF_API_UNAVAILABLE(macos);

引用自 nuclear

note:iOS8之前,data task不支援後臺session

當app不再執行而且後臺傳輸結束或者請求證書的時候,iOS會呼叫application:handleEventsForBackgroundURLSession:completionHandler:方法在後臺自動重啟應用。這個方法提供了session標識來重啟app,app應該儲存的comoletionHandler,用這個標識來建立一個後臺configuration物件,然後用這個configuration物件建立一個session.這個新的session會自動與後臺的活動關聯起來。之後當session晚餐最後一個後臺任務的適合,會呼叫代理的URLSessionDidFinishEventsForBackgroundURLSession:方法,在這個代理方法中回到主執行緒呼叫之前儲存的completionHandler,以便於讓系統知道你的app又可以再次安全的處於掛起狀態了。


Setting Download Task Delegate Callbacks

as handled by the NSURLSessionDownloadDelegate method URLSession:downloadTask:didFinishDownloadingToURL:

- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable  (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;

- 1.下載完成的回撥
- 2.需要return 儲存被下載檔案的url
- 3.當file manager在將臨時檔案移動到目的url的時候發生的錯誤,會觸發AFURLSessionDownloadTaskDidFailToMoveFileNotification通知的傳送


as handled by the NSURLSessionDownloadDelegate method URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:

- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;

在download session的整個生命週期中不定時的呼叫,反饋下載進度

as handled by the NSURLSessionDownloadDelegate method URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:

- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;

在重新啟動下載的時候被呼叫
可以獲取到檔案的偏移(已經下載的數量),預期的總量

Notifications

  • AFNetworkingTaskDidResumeNotification 重啟
  • AFNetworkingTaskDidCompleteNotification 完成
  • AFNetworkingTaskDidSuspendNotification 掛起
  • AFURLSessionDidInvalidateNotification 失效/被取消
  • AFURLSessionDownloadTaskDidFailToMoveFileNotification download task將臨時下載檔案移動到目的url時出錯

UserInfo Keys

  • AFNetworkingTaskDidCompleteResponseDataKey 非下載資料Key
  • AFNetworkingTaskDidCompleteSerializedResponseKey 序列化後的非下載資料Key
  • AFNetworkingTaskDidCompleteResponseSerializerKey 儲存序列化器的Key
  • AFNetworkingTaskDidCompleteAssetPathKey 下載完成後的檔案路徑Key
  • AFNetworkingTaskDidCompleteErrorKey 請求出錯資訊Key