NSURLSession 也不是什麼新鮮話題了,但之前一直只是簡單的使用卻沒有總結過其用法及注意事項,現在就整理一下關於NSRULSession的相關知識。 基本組成
使用需要配合三個基本的物件類型,分別是: NSURLSessionConfiguation NSURLSession
NSURLSessionTask
它們之間的關係,蘋果的官方文檔有很好的說明:
To use the NSURLSession API, your app creates a series of sessions, each of which coordinates a group of related data transfer tasks. For example, if you are writing a web browser, your app might create one session per tab or window. Within each session, your app adds a series of tasks, each of which represents a request for a specific URL (and for any follow-on URLs if the original URL returned an HTTP redirect).
從上面的說明可以看出,NSURLSession類似於平日網路互動時所謂的會話,對於NSURLSession,其本身並不會進行網路資料轉送,NSURLSession需要建立若干NSURLSessionTask來對應每次網路資料轉送。
而對於NSURLSessionTask的具體行為,取決於三個方面 NSURLSessionde 的類型(由NSURLSessionConfiguation來配置) NSURLSessionTask本身的類型 在Taks建立時,APP是否處於前端(froeground) NSURLSession的類型
NSURLSession代表著網路傳輸中的會話,iOS為其定義了三種不同的類型,並通過NSURLSessionConfiguation進行配置。
這三種config類型為: Default sessions behave similarly to other Foundation methods for downloading URLs. They use a persistent disk-based cache and store credentials in the user’s keychain. Ephemeral sessions do not store any data to disk; all caches, credential stores, and so on are kept in RAM and tied to the session. Thus, when your app invalidates the session, they are purged automatically. Background sessions are similar to default sessions, except that a separate process handles all data transfers. Background sessions have some additional limitations, described in Background Transfer Considerations.
Default Session 將cache以及credentials儲存於本地。
而Ephemeral Session 則對資料更加保密安全一些,它不會向本機存放區任何資訊,所有的cache、credentials 等存在記憶體中並和Session綁定,當Session銷毀時,所有的相關資訊也同時自動銷毀。
Background Session能夠使APP處於後台時,資料繼續傳輸。其行為與default Session類似,但是所有的資料轉送均有一個獨立的進程來管理(非本APP)。同時Background Session也有一些功能上的限制。 NSURLSession的建立與配置
對於一個Session,iOS可以設定許多相關的屬性: Private storage support for caches, cookies, credentials, and protocols in a way that is specific to a single session Authentication, tied to a specific request (task) or group of requests (session) File uploads and downloads by URL, which encourages separation of the data (the file’s contents) from the metadata (the URL and settings) Configuration of the maximum number of connections per host Per-resource timeouts that are triggered if an entire resource cannot be downloaded in a certain amount of time Minimum and maximum TLS version support Custom proxy dictionaries Control over cookie policies Control over HTTP pipelining behavior
在建立Session對象時,可以通過NSURLSessionConfiguration對象來配置Session,可選的,設定Session的delegate。
Session一旦配置完畢,就不能夠修改,除非建立另一個新的Session對象。
範例程式碼
NSURLSessionConfiguation *defaultConfigObject= [NSURLSessionConfiguation defaultSessionConfiguation];
// 對defaultConfigObject的各種屬性進行設定
.....
NSURLSession *session = [NSURLSession sessionWithConfiguration: ephemeralConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]]; NSURLSessionTask
前面說過,要想NSURLSession真正的進行網路傳輸,則需要在Session下面建立task來進行網路資訊傳輸。
iOS中有三種類型的task,它們均直接或間接的繼承於抽象父類NSURLSessionTask。
它們關係圖如下:
蘋果官方文檔對這三種task的描述如下 Data tasks send and receive data using NSData objects. Data tasks are intended for short, often interactive requests from your app to a server. Data tasks can return data to your app one piece at a time after each piece of data is received, or all at once through a completion handler. Download tasks retrieve data in the form of a file, and support background downloads while the app is not running. Upload tasks send data in the form of a file, and support background uploads while the app is not running.
DataTask樣本
NSURL *url=[NSURL URLWithString:@"www.baidu.com"];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url];
[dataTask resume];
所有的session task的初始狀態都是暫停,必須使用resume方法啟動task。 擷取NSURLSession的返回的資料
由NSURLSession擷取響應有兩種方式: 在初始化Session對象時,指定NSURLSession對象的delegate 不指定delegate,直接在task建立時指定其complete handler block。
在delegate中擷取返回資料。 需要實現兩個delegate方法: URLSession:dataTask:didReceiveData: provides the data from a request to your task, one piece at a time. URLSession:task:didCompleteWithError:indicates to your task that the data has been fully received.
利用complete block擷取返回資料,則要使用類似如下代碼
NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString: @"http://www.example.com/"]
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
NSLog(@"Got response %@ with error %@.\n", response, error);
NSLog(@"DATA:\n%@\nEND DATA\n",
[[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding]);
}] resume];
注意在上面的兩種方法中,都可以擷取到NSError對象來獲知擷取網路資料過程中出現的錯誤。但是,NSError對象僅會返回client-side的錯誤,如伺服器無法解析,網域名稱錯誤等。如果想擷取來自Server端的錯誤資訊(此時NSError對象為nil),則需要根據NSResponse對象的http status值來獲知(對HTTP協議而言) Authentication Challenges and TLS Chain Validation
在網路傳輸中我們經常會收到來自伺服器要求授權認證的請求。
在HTTP協議中,服務端會在response頭中包含WWW-Authenticate要求用戶端進行認證。在iOS中,會調用響應的delegate方法,讓使用者對認證請求作出響應。
對於那些不是來自於WWW-Authenticate的認證要求,iOS不會調用delegate的回應程式法對認證要求作出反應。
對NSURLSession的來說,當URL system loading系統遇到要求用戶端認證時,會調用delegate方法:
URLSession:didReceiveChallenge:completionHandler:
URLSession:task:didReceiveChallenge:completionHandler: NSURLSession 對象的銷毀
當我們不在需要Session對象時,需要將Session對象銷毀。可以通過以下兩種方法之一:
- (void)invalidateAndCancel
- (void)finishTasksAndInvalidate
invalidateAndCancel 函數會cancel所有的task並釋放Session對象的delegate及block,以及Session對象自身。被invalidate的Session對象不能夠在複用。
finishTasksAndInvalidate函數會立刻返回,但是不會cancel已經啟動的task,而是當這些task完成時,調用delegate的方法:
This method returns immediately without waiting for tasks to finish. Once a session is invalidated, new tasks cannot be created in the session, but existing tasks continue until completion. After the last task finishes and the session makes the last delegate call related to those tasks, the session calls the URLSession:didBecomeInvalidWithError: method on its delegate, then breaks references to the delegate and callback objects. After invalidation, session objects cannot be reused.
這裡有個地方需要注意,即:NSURLSession對象對其delegate都是強引用的,只有當Session對象invalidate, 才會釋放delegate,否則會出現memory leak。 補充
這裡有篇文章,關於NSURLSession的使用問題。我們使用task擷取網路資料,而Session則產生這些task。那麼,究竟是對每個task都使用一個Session,還是盡量使用同一個Session產生不同的task呢。文章裡面給出了答案,對於HTTP協議來說,同一個Session,會複用之前用戶端與伺服器之間的TCP串連。不用每次都握手,加速了網速(但從該篇文章裡面的配圖,看不出共用Session下省略的第二次請求的握手。。。。)
別說你會AFNetworking3.0/NSURLSession 參考文獻
URL Session Programming Guide