隨說 : 從解決業(yè)務(wù)方法中入手開始讀源碼,但是在此之前,我有個(gè)問題,為什么蘋果在iOS7之后引進(jìn)了這個(gè)NSURLSession? ,并且AFNetworking3.x后已經(jīng)將NSURLConnection廢棄,我有個(gè)原則,你會(huì)用一個(gè)東西去解決一些問題之后,應(yīng)該去問問自己為什么要用這個(gè)東西,AFNetworking3.x是基于NSURLSession來封裝的, 現(xiàn)在來總結(jié)一下NSURLSession的用法
Xcode 7+ is required.NSURLConnectionOperation support has been removed
解決這個(gè)疑惑, 請(qǐng)你拜讀以下的文章
NSURLSession 入門教程
別說你會(huì)AFNetworking3.0/NSURLSession
忘記NSURLConnection,擁抱NSURLSession吧钓辆!
1. NSURLSession是什么?##
先來看兩個(gè)圖
- NSURLSession負(fù)責(zé)發(fā)送和接收HTTP的請(qǐng)求蹈垢。
- NSURLSession由NSURLSessionConfiguration(我理解為一份配置)和NSURLSessionDelegate & NSOperationQueue(一份協(xié)議)組成
每一個(gè)NSURLSession對(duì)象都是根據(jù)一個(gè)NSURLSessionConfiguration初始化的定欧,該NSURLSessionConfiguration指定了上面提到的政策酵熙,以及一系列為了提高移動(dòng)設(shè)備性能而專門添加的新選項(xiàng)凌彬。
而NSURLSession的另一重要組成部分是會(huì)話任務(wù)变屁,它負(fù)責(zé)處理數(shù)據(jù)的加載议惰,以及客戶端與服務(wù)器之間的文件和數(shù)據(jù)的上傳下載服務(wù)践惑。NSURLSessionTask與NSURLConnection是及其相似的腹泌,因?yàn)樗?fù)責(zé)加載數(shù)據(jù),而主要的區(qū)別在于尔觉,任務(wù)共享它們父類NSURLSession的共同委托(common delegate)凉袱。
/*
* The shared session uses the currently set global NSURLCache,
* NSHTTPCookieStorage and NSURLCredentialStorage objects.
*/
// 創(chuàng)建默認(rèn)NSURLSession對(duì)象 默認(rèn)使用defaultSessionConfiguration
// 使用的是全局的cache,cookie和credential storage objects來創(chuàng)建configuration對(duì)象
// 通過默認(rèn)配置來創(chuàng)建一個(gè)NSURLSession并且不需要協(xié)議
+ (NSURLSession *)sharedSession;
/*
* Customization of NSURLSession occurs during creation of a new session.
* If you only need to use the convenience routines with custom
* configuration options it is not necessary to specify a delegate.
* If you do specify a delegate, the delegate will be retained until after
* the delegate has been sent the URLSession:didBecomeInvalidWithError: message.
*/
/*
// 通過一份連接配置來創(chuàng)建一個(gè)NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
// 通過一份連接配置和一份協(xié)議來創(chuàng)建一個(gè)NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
2. NSURLSessionConfiguration是什么?##
我理解為一份配置, 而這份配置就是儲(chǔ)存這個(gè)整個(gè)連接的一些基本屬性例如 : 會(huì)話屬性,如超時(shí)值侦铜,高速緩存的政策和額外的HTTP標(biāo)頭等
三種創(chuàng)建方式 :
// 創(chuàng)建一個(gè)使用磁盤堅(jiān)持全局緩存专甩,證書和cookie的默認(rèn)配置對(duì)象。
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
// 類似于默認(rèn)配置钉稍,用于“private” sessions涤躲,對(duì)于cache, cookie, or credential storage objects的非永久存儲(chǔ)。
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
// 讓會(huì)話在后臺(tái)執(zhí)行上傳或下載任務(wù)贡未。當(dāng)應(yīng)用程序本身被暫椭钟#或終止轉(zhuǎn)讓甚至繼續(xù)。iOS 8.0后提供的屬性
// 做遠(yuǎn)程push通知或是應(yīng)用程序掛起的時(shí)候就要用到這個(gè)configuration
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);
常規(guī)配置屬性 :
/* 常規(guī)屬性 - 常規(guī)屬性有7個(gè) */
/*background 模式下需要標(biāo)識(shí) */
@property (nullable, readonly, copy) NSString *identifier;
/*超時(shí)屬性 ,用作設(shè)置timeoutIntervalForRequest時(shí)間內(nèi), 如果沒有請(qǐng)求數(shù)據(jù)發(fā)送,則請(qǐng)求超時(shí) */
@property NSTimeInterval timeoutIntervalForRequest;
/* 超時(shí)屬性, 用作設(shè)置timeoutIntervalForResource時(shí)間內(nèi),如果沒有返回響應(yīng),則響應(yīng)超時(shí) */
@property NSTimeInterval timeoutIntervalForResource;
/* 網(wǎng)絡(luò)服務(wù)類型 */
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
{
NSURLNetworkServiceTypeDefault = 0, // Standard internet traffic
NSURLNetworkServiceTypeVoIP = 1, // Voice over IP control traffic
NSURLNetworkServiceTypeVideo = 2, // Video traffic
NSURLNetworkServiceTypeBackground = 3, // Background traffic
NSURLNetworkServiceTypeVoice = 4 // Voice data
};
// 這個(gè)屬性一般用于音頻處理流
@property NSURLRequestNetworkServiceType networkServiceType;
// 設(shè)置這個(gè)屬性, 會(huì)為所有的NSURLSessionTask加上基礎(chǔ)request頭,可以統(tǒng)一請(qǐng)求頭
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
// 一個(gè)布爾值俊卤,確定是否通過蜂窩網(wǎng)絡(luò)連接, 默認(rèn)為YES ,
@property BOOL allowsCellularAccess;
// iOS8.0后才能用, backgroundSessionConfigurationWithIdentifier中的identifier中對(duì)應(yīng)使用, 被標(biāo)識(shí)的文件,會(huì)在后臺(tái)中下載
@property (nullable, copy) NSString *sharedContainerIdentifier NS_AVAILABLE(10_10, 8_0);
cookie策略配置
// NSHTTPCookieAcceptPolicy, 配置處理cookie的策略,
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
NSHTTPCookieAcceptPolicyAlways, // 總是接受cookie
NSHTTPCookieAcceptPolicyNever, // 總是不接受cookie
NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain // 只從DocumentDomain文件中接受緩存
};
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy
// HTTPCookieStorage類, 提供了一些方法, 這個(gè)類的作用是儲(chǔ)存請(qǐng)求的cookie, 待下一次請(qǐng)求的時(shí)候, 會(huì)再次將上次保存下來了的cookie繼續(xù)去請(qǐng)求
@property(retain) NSHTTPCookieStorage *HTTPCookieStorage
// 一個(gè)布爾值嫩挤,確定是否請(qǐng)求應(yīng)包含來自cookie存儲(chǔ)的cookie。The default value is YES
@property BOOL HTTPShouldSetCookies
安全策略配置
// TLSMaximumSupportedProtocol 和 TLSMinimumSupportedProtocol 確定是否支持SSLProtocol版本的會(huì)話消恍。
/* The minimum allowable versions of the TLS protocol, from <Security/SecureTransport.h> SSL協(xié)議*/
@property SSLProtocol TLSMinimumSupportedProtocol;
/* The maximum allowable versions of the TLS protocol, from <Security/SecureTransport.h> SSL協(xié)議*/
@property SSLProtocol TLSMaximumSupportedProtocol;
// NSURLCredentialStorage類管理的是task會(huì)話中使用任務(wù)憑據(jù)存儲(chǔ)對(duì)象岂昭。
@property(retain) NSURLCredentialStorage *URLCredentialStorage
緩存策略配置
// NSURLRequestCachePolicy枚舉
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
// 默認(rèn)的緩存策略, 如果緩存不存在哺哼,直接從服務(wù)端獲取佩抹。如果緩存存在叼风,會(huì)根據(jù)response中的Cache-Control字段判斷下一步操作,如: Cache-Control字段為must-revalidata, 則詢問服務(wù)端該數(shù)據(jù)是否有更新棍苹,無(wú)更新的話直接返回給用戶緩存數(shù)據(jù)无宿,若已更新,則請(qǐng)求服務(wù)端.
NSURLRequestUseProtocolCachePolicy = 0,
// 忽略本地緩存數(shù)據(jù)枢里,直接請(qǐng)求服務(wù)端.
NSURLRequestReloadIgnoringLocalCacheData = 1,
// Unimplemented 未實(shí)現(xiàn)枚舉值
NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented
// 相當(dāng)于NSURLRequestReloadIgnoringLocalCacheData, 忽略本地緩存數(shù)據(jù)孽鸡,直接請(qǐng)求服務(wù)端.
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
// 有緩存就使用,不管其有效性(即忽略Cache-Control字段), 無(wú)則請(qǐng)求服務(wù)端.
NSURLRequestReturnCacheDataElseLoad = 2,
// 加載本地緩存. 有就加載, 沒有就當(dāng)加載失敗處理. (確定當(dāng)前無(wú)網(wǎng)絡(luò)時(shí)使用)
NSURLRequestReturnCacheDataDontLoad = 3,
// Unimplemented 未實(shí)現(xiàn)枚舉值
NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented
};
/* 請(qǐng)求的默認(rèn)緩存策略 ,有以上幾種方式*/
// 指定了一個(gè)請(qǐng)求的緩存響應(yīng)的方式,和應(yīng)該在什么時(shí)候返回
@property NSURLRequestCachePolicy requestCachePolicy;
/* The URL resource cache, or nil to indicate that no caching is to be performed */
// 是會(huì)話使用的緩存栏豺。默認(rèn)情況下彬碱,NSURLCache 的+ sharedURLCache 會(huì)被使用
@property (nullable, retain) NSURLCache *URLCache;
設(shè)置HTTP策略和代理屬性
/* The proxy dictionary, as described by <CFNetwork/CFHTTPStream.h> */
// 指定了Session(會(huì)話)連接中的代理服務(wù)器。同樣地奥洼,大多數(shù)面向消費(fèi)者的應(yīng)用程序都不需要代理巷疼,所以基本上不需要配置這個(gè)屬性。
@property (nullable, copy) NSDictionary *connectionProxyDictionary;
/* The maximum number of simultanous persistent connections per host */
// 是 Foundation 框架中URL加載系統(tǒng)的一個(gè)新的配置選項(xiàng)灵奖。它曾經(jīng)被用于NSURLConnection管理私人連接池〗姥兀現(xiàn)在有了NSURLSession,開發(fā)者可以在需要時(shí)限制連接到特定主機(jī)的數(shù)量瓷患。
@property NSInteger HTTPMaximumConnectionsPerHost;
/* Allow the use of HTTP pipelining */
// 也出現(xiàn)在NSMutableURLRequest骡尽,它可以被用于開啟HTTP管道,這可以顯著降低請(qǐng)求的加載時(shí)間擅编,但是由于沒有被服務(wù)器廣泛支持攀细,默認(rèn)是禁用的。
@property BOOL HTTPShouldUsePipelining;
3. NSURLSessionTask是什么?##
NSURLSessionTask是一個(gè)抽象子類爱态,它有三個(gè)具體的子類是可以直接使用的:NSURLSessionDataTask谭贪,NSURLSessionUploadTask和NSURLSessionDownloadTask。這三個(gè)類封裝了現(xiàn)代應(yīng)用程序的三個(gè)基本網(wǎng)絡(luò)任務(wù):獲取數(shù)據(jù)肢藐,比如JSON或XML故河,以及上傳下載文件。
NSURLSessionTask的三個(gè)子類completionHandler處理方式有點(diǎn)不同
NSURLSessionDataTask (JSON或XML) :
數(shù)據(jù)在完成時(shí)立即返回,
NSURLSessionDownloadTask(下載文件) :
下載任務(wù)將數(shù)據(jù)寫入本地的臨時(shí)文件吆豹。completionHandler將文件從它的臨時(shí)位置移動(dòng)到一個(gè)永久位置鱼的,這個(gè)永久位置就是塊的返回值。它會(huì)帶回已下載文件的一個(gè)臨時(shí)的文件路徑location.
NSURLSessionUploadTask(上傳文件)
因?yàn)橐话銇碚f痘煤,服務(wù)端對(duì)于一個(gè)上傳任務(wù)的響應(yīng)也會(huì)有相關(guān)數(shù)據(jù)返回凑阶,所以NSURLSessionUploadTask
3.1 已經(jīng)有了NSURLSessionDataTask, 為什么還有繼承多一層NSURLSessionUploadTask??###
從兩者提供的對(duì)應(yīng)task 生成的方法能看。比如使用dataTask來進(jìn)行上傳任務(wù)的時(shí)候衷快,需要指定HTTPMethod為POST或PUT宙橱,并且提供的數(shù)據(jù)(NSData)得賦值給request.HTTPBody。而使用uploadTask來進(jìn)行上傳任務(wù)的時(shí)候,只需要使用- uploadTaskWithRequest:fromData:或- uploadTaskWithRequest:fromFile:之類的方法师郑,其中參數(shù)的話只需要根提供數(shù)據(jù)(NSData)或者數(shù)據(jù)的磁盤位置(NSURL*fileURL)就可以構(gòu)造出一個(gè)上傳的session task了环葵,簡(jiǎn)化了操作。
NSURLSessionTask 的屬性
// 任務(wù)標(biāo)識(shí)宝冕,唯一確定一個(gè)任務(wù)
@property (readonly) NSUInteger taskIdentifier; /* an identifier for this task, assigned by and unique to the owning session */
// 上一個(gè)請(qǐng)求對(duì)象
@property (nullable, readonly, copy) NSURLRequest *originalRequest; /* may be nil if this is a stream task */
// 當(dāng)前請(qǐng)求對(duì)象
@property (nullable, readonly, copy) NSURLRequest *currentRequest; /* may differ from originalRequest due to http server redirection */
// 服務(wù)器的響應(yīng)數(shù)據(jù)
@property (nullable, readonly, copy) NSURLResponse *response; /* may be nil if no response has been received */
/* 如果不存在響應(yīng)實(shí)體, 字節(jié)數(shù)可以為零
* or NSURLSessionTransferSizeUnknown if it is not possible
* to know how many bytes will be transferred.
*/
/* number of body bytes already received */
// 已經(jīng)接收到的數(shù)據(jù)量
@property (readonly) int64_t countOfBytesReceived;
/* number of body bytes already sent */
// 已經(jīng)發(fā)送的數(shù)據(jù)量
@property (readonly) int64_t countOfBytesSent;
/* number of body bytes we expect to send, derived from the Content-Length of the HTTP request */
// 所要發(fā)送的總數(shù)據(jù)量
@property (readonly) int64_t countOfBytesExpectedToSend;
/* number of byte bytes we expect to receive, usually derived from the Content-Length header of an HTTP response. */
// 所要接收到的總數(shù)據(jù)量
@property (readonly) int64_t countOfBytesExpectedToReceive;
/*
* The taskDescription property is available for the developer to
* provide a descriptive label for the task.
*/
// 任務(wù)描述.不知道用處在什么地方
@property (nullable, copy) NSString *taskDescription;
/* -cancel returns immediately, but marks a task as being canceled.
* The task will signal -URLSession:task:didCompleteWithError: with an
* error value of { NSURLErrorDomain, NSURLErrorCancelled }. In some
* cases, the task may signal other work before it acknowledges the
* cancelation. -cancel may be sent to a task that has been suspended.
*/
// 取消任務(wù)
- (void)cancel;
/*
* Suspending a task will prevent the NSURLSession from continuing to
* load data. There may still be delegate calls made on behalf of
* this task (for instance, to report data received while suspending)
* but no further transmissions will be made on behalf of the task
* until -resume is sent. The timeout timer associated with the task
* will be disabled while a task is suspended. -suspend and -resume are
* nestable.
*/
// 暫停任務(wù)
- (void)suspend;
// 繼續(xù)任務(wù) / 開始任務(wù)
- (void)resume;
/*
* The current state of the task within the session.
*/
// 會(huì)話狀態(tài),NSURLSessionTaskState 枚舉 有4個(gè)狀態(tài)
@property (readonly) NSURLSessionTaskState state;
/*
* The error, if any, delivered via -URLSession:task:didCompleteWithError:
* This property will be nil in the event that no error occured.
*/
// 錯(cuò)誤信息 通過-URLSession:task:didCompleteWithError:來傳遞
@property (nullable, readonly, copy) NSError *error;
NSURLSessionDataTask 與 NSURLSessionUploadTask都沒有擴(kuò)展方法和屬性
NSURLSessionDownloadTask 擴(kuò)展了一個(gè)方法
// 提供了一個(gè)取消任務(wù)的方法张遭,而且會(huì)保存用于以后繼續(xù)任務(wù)的信息,方法如下:
- (void)cancelByProducingResumeData:(void (^)(NSData * __nullable resumeData))completionHandler;
總結(jié)一下 !##
與NSURLConnection類似地梨,除了同名類NSURLSession菊卷,NSURLSession也是指一組相互依賴的類。NSURLSession包括與之前相同的組件宝剖,例如NSURLRequest, NSURLCache等洁闰。NSURLSession的不同之處在于,它把 NSURLConnection替換為NSURLSession, NSURLSessionConfiguration万细,以及3個(gè)NSURLSessionTask的子類NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask, IOS9之后又多了一個(gè)NSURLSessionStreamTask
NSURLSession最直接的改善就是提供了配置每個(gè)會(huì)話的緩存扑眉,協(xié)議,cookie和證書政策(credential policies)雅镊,甚至跨應(yīng)用程序共享它們的能力. 一種很好的設(shè)計(jì)思想, 將網(wǎng)絡(luò)基礎(chǔ)架構(gòu)和部分應(yīng)用程序獨(dú)立工作襟雷,互相不會(huì)干擾.
一個(gè)NSURLSession(會(huì)話), 是通過一份NSURLSessionConfiguration(對(duì)于會(huì)話如何產(chǎn)生請(qǐng)求刃滓,提供了相當(dāng)多的控制和靈活性仁烹。從網(wǎng)絡(luò)訪問性能,到cookie咧虎,安全性卓缰,緩存策略,自定義協(xié)議砰诵,啟動(dòng)事件設(shè)置征唬,以及用于移動(dòng)設(shè)備優(yōu)化的幾個(gè)新屬性)從而初始化一個(gè)NSURLSession(會(huì)話), 當(dāng)然同時(shí)也可以遵守一些Delegate協(xié)議,從而擴(kuò)展一些方法
定義NSURLSessionConfiguration(配置) - > (可選)遵守協(xié)議(NSURLSessionDelegate) ->創(chuàng)建NSURLSession(會(huì)話) ->根據(jù)實(shí)質(zhì)需求定義NSURLSessionTask(任務(wù))
后記 : 寫文章的過程中,是對(duì)自己的思維的一個(gè)總結(jié),翻查了很多文檔,同時(shí)也交叉對(duì)比了一些文檔與文章中的話,只有理解了基礎(chǔ), 才可以玩得很6, 下一章我將會(huì)開始扣AFNetworking 3.0+框架中,是怎樣設(shè)計(jì)這些類的使用的.