Github : Jerry4me, Demo : JRBgSessionDemo
前言
本文主要是結(jié)合官方文檔, 挖掘NSURLSession的類層次結(jié)構(gòu)及其聯(lián)系, 總結(jié)出關(guān)于NSURLSession的一些關(guān)鍵點(diǎn)及其用法.
關(guān)于NSURLSession為什么能取代NSURLConnection, 其優(yōu)勢是什么, 及其NSURLSession API的概述, 見
關(guān)于ATS, HTTP/2, 以及iOS9 NSURLSession新特性 : sharedCookies, streamTask和taskMetrics, 見
以上兩篇文章都是我看wwdc視頻然后總結(jié)出來的文章, 大家感興趣的可以先了解了解. 如果不想知道那么多, 只想知道怎么用NSURLSession, 那就直接看本文的正文.
*了解URL Loading System
目錄
-
介紹NSURLSession相關(guān)類
-
身份驗(yàn)證和自定義TLS
-
[App Transport Security](#App Transport Security)
-
[NSURLSession 工作流程](#NSURLSession 工作流程)
-
[后臺傳輸及其用法](#Background Transport)
-
[NSURLSession API](#NSURLSession API)
-
[其他一些注意點(diǎn)](#Something else Important)
NSURLSession
NSURLSession
- 支持data, ftp, http(s)協(xié)議, 同時(shí)支持代理服務(wù)器和socks網(wǎng)關(guān).
- 支持http/1.1, http/2, spdy協(xié)議, 但同時(shí)需要服務(wù)器支持ALPN和NPN.
ALPN與NPN
- ALPN(Application Layer Protocol Negotiation伯复,應(yīng)用層協(xié)議協(xié)商)
- NPN(Next Protocol Negotiation结胀,下一代協(xié)議協(xié)商)
NPN是服務(wù)端發(fā)送它支持的HTTP協(xié)議列表, 供客戶端選擇; 而ALPN則相反, 由客戶端發(fā)送它支持的HTTP協(xié)議列表, 供服務(wù)端選擇. 如果缺少NPN/ALPN其中一個(gè), 則無法使用HTTP/2通信. 具體請見為什么我們應(yīng)該盡快支持 ALPN.
NSURLSession相關(guān)類為 :
- NSURLSession
- NSURLSessionConfiguration
- NSURLSessionDelegate
- NSURLSessionTask
- NSURLSessionTaskMetrics
- NSURLSessionTaskTransactionMetrics
他們相互的關(guān)系如下 :
NSURLSession
session分為 :
- 全局共享單例session :
NSURLSession sharedSession
, 有一定的局限性 - 自定義session : 自定義配置文件, 設(shè)置代理, 大部分時(shí)間我們都是用這個(gè)
- 后臺session : 也是自定義session的一種, 只是他專門用于做后臺上傳/下載任務(wù)
session為哪一種類型完全由其內(nèi)部的Configuration而定.
NSURLSessionConfiguration
配置分為 :
- defaultSessionConfiguration : 系統(tǒng)默認(rèn)
- ephemeralSessionConfiguration : 僅內(nèi)存緩存, 不做磁盤緩存的配置
- backgroundSessionConfiguration : 這里需要指定一個(gè)identifier, identifier用來后臺重連session對象. (做后臺上傳/下載就是這個(gè)config)
另外, 我們還可以給Configuration對象再自定義一些屬性, 例如每端口的最大并發(fā)HTTP請求數(shù)目, 以及是否允許蜂窩網(wǎng)絡(luò), 請求緩存策略, 請求超時(shí), cookies/證書存儲策略等等
NSURLSessionDelegate
session管理的一組tasks共享一個(gè)代理, 不想實(shí)現(xiàn)代理方法時(shí), 代理傳nil即可.
代理協(xié)議分為 :
-
NSURLSessionDelegate
: session-level的代理方法 -
NSURLSessionTaskDelegate
: task-level面向all的代理方法 -
NSURLSessionDataDelegate
: task-level面向data和upload的代理方法 -
NSURLSession?Download?Delegate
: task-level的面向download的代理方法 -
NSURLSessionStreamDelegate
: task-level的面向stream的代理方法
NSURLSessionTask
session task類型分為 :
-
NSURLSessionTask
: Task的抽象基類 -
NSURLSessionDataTask
: 以NSData的形式接收一個(gè)URLRequest的內(nèi)容 -
NSURLSessionUploadTask
: 上傳NSData或者本地磁盤中的文件, 完成后以NSData的形式接收一個(gè)URLRequest的響應(yīng) -
NSURLSessionDownloadTask
: 下載完成后返回臨時(shí)文件在本地磁盤的URL路徑 -
NSURLSessionStreamTask
: 用于建立一個(gè)TCP/IP連接
NSURLSessionTaskMetrics 和 NSURLSessionTaskTransactionMetrics
對發(fā)送請求/DNS查詢/TLS握手/請求響應(yīng)等各種環(huán)節(jié)時(shí)間上的統(tǒng)計(jì). 更易于我們檢測, 分析我們App的請求緩慢到底是發(fā)生在哪個(gè)環(huán)節(jié), 并對此進(jìn)行優(yōu)化提升我們APP的性能.
NSURLSessionTaskMetrics對象與NSURLSessionTask對象一一對應(yīng). 每個(gè)NSURLSessionTaskMetrics對象內(nèi)有3個(gè)屬性 :
- taskInterval : task從開始到結(jié)束總共用的時(shí)間
- redirectCount : task重定向的次數(shù)
- transactionMetrics : 一個(gè)task從發(fā)出請求到收到數(shù)據(jù)過程中派生出的每個(gè)子請求, 它是一個(gè)裝著許多NSURLSessionTaskTransactionMetrics對象的數(shù)組. 每個(gè)對象都代表下圖的一個(gè)子過程
API很簡單, 就一個(gè)方法 : - (void)URLSession: task: didFinishCollectingMetrics:
, 當(dāng)收集完成的時(shí)候就會調(diào)用該方法.
身份驗(yàn)證和自定義TLS
當(dāng)一個(gè)服務(wù)器請求身份驗(yàn)證或TLS握手期間需要提供證書的話, URLSession會調(diào)用他的代理方法
URLSession:?did?Receive?Challenge:?completion?Handler:?
去處理.如果你沒有實(shí)現(xiàn)該代理方法, URLSession就會這么做 :
- 使用身份認(rèn)證信息作為請求URL的一部分(如果可用的話)
- 在用戶的keychain中查找網(wǎng)絡(luò)密碼和證書(in macOS), 在app的keychain中查找(in iOS)
- 如果證書還是不可用或服務(wù)器拒絕該證書, 就會繼續(xù)缺少身份認(rèn)證的連接.
- 對于HTTP(S)連接, 請求失敗并返回一個(gè)狀態(tài)碼, 可能會提供一些替代的內(nèi)容, 例如一個(gè)私人網(wǎng)站的公共網(wǎng)頁.
- 對于其他URL類型(如FTP等), 則連接請求失敗, 直接返回錯(cuò)誤信息
App Transport Security
從iOS9開始支持ATS, 且默認(rèn)ATS只支持發(fā)送HTTPS請求, 不允許發(fā)送不安全的HTTP請求. 如果用戶需要發(fā)送HTTP請求需要在info.plist
中配置一些東西.
詳情在文章開頭的iOS9 ATS HTTP/2 NSURLSession中說得很詳細(xì), 想了解的可以進(jìn)去閱讀.
NSURLSession 工作流程
那么如何使用NSURLSession像從前用NSURLConnection那樣發(fā)送一個(gè)請求呢?
// 設(shè)置配置
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
/** 設(shè)置其他配置屬性 **/
// 代理隊(duì)列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
// 創(chuàng)建session
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:queue];
// 利用session創(chuàng)建n個(gè)task
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
// 開始
[task resume];
然后就可以在代理方法中處理各種事情了. 簡單吧? 下面分task說明代理方法的調(diào)用情況..
身份驗(yàn)證或TLS握手
這是所有task都必須經(jīng)歷的一個(gè)過程. 當(dāng)一個(gè)服務(wù)器請求身份驗(yàn)證或TLS握手期間需要提供證書的話, URLSession會調(diào)用他的代理方法URLSession:?did?Receive?Challenge:?completion?Handler:?
去處理., 另外, 如果連接途中收到服務(wù)器返回需要身份認(rèn)證的response, 也會調(diào)用該代理方法.
重定位response
這也是所有task都有可能經(jīng)歷的一個(gè)過程, 如果response是HTTP重定位, session會調(diào)用代理的URLSession:?task:?will?Perform?HTTPRedirection:?new?Request:?completion?Handler:
方法. 這里需要調(diào)用completionHandler告訴session是否允許重定位, 或者重定位到另一個(gè)URL, 或者傳nil表示重定位的響應(yīng)body有效并返回. 如果代理沒有實(shí)現(xiàn)該方法, 則允許重定位直到達(dá)到最大重定位次數(shù).
DataTask
- 對于一個(gè)data task來說, session會調(diào)用代理的
URLSession:?data?Task:?did?Receive?Response:?completion?Handler:?
方法, 決定是否將一個(gè)data dask轉(zhuǎn)換成download task, 然后調(diào)用completion回調(diào)繼續(xù)接收data或下載data.
- 如果你的app選擇轉(zhuǎn)換成download task, session會調(diào)用代理的
URLSession:?data?Task:?did?Become?Download?Task:?
方法并把新的download task對象以方法參數(shù)的形式傳給你. 之后代理不會再收到data task的回調(diào)而是轉(zhuǎn)為收到download task的回調(diào)
在服務(wù)器傳輸數(shù)據(jù)給客戶端期間, 代理會周期性地收到
URLSession:?data?Task:?did?Receive?Data:?
回調(diào)session會調(diào)用
URLSession:?data?Task:?will?Cache?Response:?completion?Handler:?
詢問你的app是否允許緩存. 如果代理不實(shí)現(xiàn)這個(gè)方法的話, 默認(rèn)使用session綁定的Configuration的緩存策略.
DownloadTask
對于一個(gè)通過
download?Task?With?Resume?Data:?
創(chuàng)建的下載任務(wù), session會調(diào)用代理的URLSession:?download?Task:?did?Resume?At?Offset:?expected?Total?Bytes:?
方法.在服務(wù)器傳輸數(shù)據(jù)給客戶端期間, 調(diào)用
URLSession:?download?Task:?did?Write?Data:?total?Bytes?Written:?total?Bytes?Expected?To?Write:
給用戶傳數(shù)據(jù)
- 當(dāng)用戶暫停下載時(shí), 調(diào)用
cancel?By?Producing?Resume?Data:?
給用戶傳已下好的數(shù)據(jù). - 如果用戶想要恢復(fù)下載, 把剛剛的resumeData以參數(shù)的形式傳給
download?Task?With?Resume?Data:?
方法創(chuàng)建新的task繼續(xù)下載.
- 如果download task成功完成了, 調(diào)用
URLSession:?download?Task:?did?Finish?Downloading?To?URL:
把臨時(shí)文件的URL路徑給你. 此時(shí)你應(yīng)該在該代理方法返回以前讀取他的數(shù)據(jù)或者把文件持久化.
UploadTask
上傳數(shù)據(jù)去服務(wù)器期間, 代理會周期性收到URLSession:?task:?did?Send?Body?Data:?total?Bytes?Sent:?total?Bytes?Expected?To?Send:
回調(diào)并獲得上傳進(jìn)度的報(bào)告.
StreamTask
如果任務(wù)的數(shù)據(jù)是由一個(gè)stream發(fā)出的, session就會調(diào)用代理的URLSession:?task:?need?New?Body?Stream:?方法去獲取一個(gè)NSInputStream對象并提供一個(gè)新請求的body data.
task completion
任何task完成的時(shí)候, 都會調(diào)用URLSession:?task:?did?Complete?With?Error:?
方法, error有可能為nil(請求成功), 不為nil(請求失敗)
請求失敗, 但是該任務(wù)是可恢復(fù)下載的, 那么error對象的userInfo字典里有一個(gè)
NSURLSession?Download?Task?Resume?Data
對應(yīng)的value, 你應(yīng)該把這個(gè)值傳給download?Task?With?Resume?Data:?
方法重新恢復(fù)下載請求失敗, 但是任務(wù)無法恢復(fù)下載, 那么應(yīng)該重新創(chuàng)建一個(gè)下載任務(wù)并從頭開始下載.
因?yàn)槠渌?如服務(wù)器錯(cuò)誤等等), 創(chuàng)建并恢復(fù)請求.
Note
NSURLSession不會收到服務(wù)器傳來的錯(cuò)誤, 代理只會收到客戶端出現(xiàn)的錯(cuò)誤, 例如無法解析主機(jī)名或無法連接上主機(jī)等等. 客戶端錯(cuò)誤定義在URL Loading System Error Codes. 服務(wù)端錯(cuò)誤通過HTTP狀態(tài)法進(jìn)行傳輸, 詳情請看NSHTTPURLResponse和NSURLResponse類.
銷毀session
如果你不再需要一個(gè)session了, 一定要調(diào)用它的invalidateAndCancel
或finishTasksAndInvalidate
方法. (前者是取消所有未完成的任務(wù)然后使session失效, 后者是等待正在執(zhí)行的任務(wù)完成之后再使session失效). 否則的話, 有可能造成內(nèi)存泄漏. 另外, session失效后會調(diào)用URLSession:?did?Become?Invalid?With?Error:
方法, 之后session釋放對代理的強(qiáng)引用.
Background Transport
需要注意的是, 在后臺session中, 一些代理方法將失效. 下面說一些使用后臺session的注意點(diǎn) :
- 后臺session必須提供一個(gè)代理處理突發(fā)事件
- 只支持HTTP(S)協(xié)議. 其他協(xié)議都不可用.
- 只支持上傳/下載任務(wù), data任務(wù)不支持.
- 后臺任務(wù)有數(shù)量限制
- 當(dāng)任務(wù)數(shù)量到達(dá)系統(tǒng)指定的臨界值的時(shí)候, 一些后臺任務(wù)就會被取消. 也就是說, 一個(gè)需要長時(shí)間上傳/下載的任務(wù)很可能會被系統(tǒng)取消然后有可能過一會再重新開始, 所以支持?jǐn)帱c(diǎn)續(xù)傳很重要.
- 如果一個(gè)后臺傳輸任務(wù)是在app在后臺的時(shí)候開啟的, 那么這個(gè)任務(wù)很可能會出于對性能的考慮隨時(shí)被系統(tǒng)取消掉. . (相當(dāng)于session的Configuration對象的discretionary屬性為true.)
后臺session限制確實(shí)很多, 所以盡可能使用前臺session做事情.
Note
后臺session最好用來傳輸一些支持?jǐn)帱c(diǎn)續(xù)傳大文件. 或?qū)@個(gè)過程進(jìn)行一些針對性的優(yōu)化
- 最好把文件先壓縮成zip/tar等壓縮文件再上傳/下載.
- 把大文件按數(shù)據(jù)段分別發(fā)送, 發(fā)送完之后服務(wù)端再把數(shù)據(jù)拼接起來.
- 上傳的時(shí)候服務(wù)端應(yīng)該返回一個(gè)標(biāo)識符, 這樣可以追蹤傳輸?shù)臓顟B(tài), 及時(shí)做出傳輸?shù)恼{(diào)整
- 增加一個(gè)web代理服務(wù)器中間層, 以促進(jìn)上述的優(yōu)化
Usage
那么如何使用這個(gè)后臺傳輸呢?
創(chuàng)建一個(gè)后臺session
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.Jerry4me.backgroundSessionIdentifier"];
_backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];創(chuàng)建一個(gè)upload or download task
NSURL *URL = [NSURL URLWithString:@"http://www.bz55.com/uploads/allimg/140402/137-140402153504.jpg"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
self.task = [self.session downloadTaskWithRequest:request];
/**注意 : 后臺任務(wù)不能使用帶有completionHandler的方法創(chuàng)建 **/
/**注意 : 如果任務(wù)只想在app進(jìn)入后臺后才處理, 那么可不調(diào)用[task resume]主動執(zhí)行, 待程序進(jìn)入后臺后會自動執(zhí)行 **/
- 我們等下載到一半后進(jìn)入后臺, 打開App Switcher過一會可以發(fā)現(xiàn), 圖片下載完之后就會顯示在應(yīng)用程序上. 方法調(diào)用順序?yàn)?: 下面四個(gè)方法全部都是app在后臺時(shí)調(diào)用的
2017-03-24 14:17:09.458415 JRBgSessionDemo[2766:1080861] 下載中 - 58%
2017-03-24 14:17:09.567957 JRBgSessionDemo[2766:1080861] 下載中 - 59%
2017-03-24 14:17:16.916830 JRBgSessionDemo[2766:1080828] -[AppDelegate application:handleEventsForBackgroundURLSession:completionHandler:]
2017-03-24 14:17:16.951185 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSession:downloadTask:didFinishDownloadingToURL:]
2017-03-24 14:17:16.953951 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSession:task:didCompleteWithError:]
2017-03-24 14:17:16.954574 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSessionDidFinishEventsForBackgroundURLSession:]
總結(jié)后臺傳輸
- 盡量用真機(jī)進(jìn)行調(diào)試, 模擬器會跳過某一兩個(gè)方法
- 只能進(jìn)行upload/download task, 不能進(jìn)行data task
- 不能使用帶completionHandler的方法創(chuàng)建task, 否則程序直接掛掉
- Applecation里的completionHandler必須存儲起來, 等你處理完所有事情之后再調(diào)用告訴系統(tǒng)可以進(jìn)行Snapshot和掛起app了
- 后臺下載最好支持?jǐn)帱c(diǎn)續(xù)傳, 因?yàn)槿蝿?wù)有可能會被系統(tǒng)主動取消(例如系統(tǒng)性能下降了, 資源不夠用的情況下)
后臺傳輸?shù)腄emo在文章頭部的地方, 也可以點(diǎn)這里進(jìn)去
NSURLSession API
-
創(chuàng)建Session
-
+ session?With?Configuration:??
: 創(chuàng)建一個(gè)指定配置的session -
+ session?With?Configuration:??delegate:??delegate?Queue:??
: 創(chuàng)建一個(gè)指定配置, 代理和代理方法執(zhí)行隊(duì)列的session -
shared?Session
: 返回session單例
-
-
配置Session
-
configuration
: 配置 -
delegate
: 代理對象 -
delegateQueue
: 代理方法的執(zhí)行隊(duì)列 -
sessionDescription
: app定義的對于該session的描述
-
-
添加data任務(wù)
-
- dataTaskWithURL:
: 獲取指定URL內(nèi)容 -
- dataTaskWithURL:completionHandler:
: 獲取指定URL內(nèi)容, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法) -
- data?Task?With?Request:??
: 獲取指定URLRequest內(nèi)容 -
- data?Task?With?Request:??completionHandler:
: 獲取指定URLRequest內(nèi)容, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法)
-
-
添加download任務(wù)
-
- downloadTaskWithURL:
: 下載指定URL內(nèi)容 -
- downloadTaskWithURL:completionHandler:
: 下載指定URL內(nèi)容, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法) -
- downloadTask?With?Request:??
: 下載指定URLRequest內(nèi)容 -
- downloadTask?With?Request:??completionHandler:
: 下載指定URLRequest內(nèi)容, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法) -
- downloadTask?With?ResumeData:??
: 創(chuàng)建一個(gè)之前被取消/下載失敗的download task -
- downloadTask?With?ResumeData:??completionHandler:
: 創(chuàng)建一個(gè)之前被取消/下載失敗的download task, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法)
-
-
添加upload任務(wù)
-
- upload?Task?With?Request:??from?Data:??
: 通過HTTP請求發(fā)送data給指定URL -
- upload?Task?With?Request:??from?Data:completionHandler:
: 通過HTTP請求發(fā)送data給指定URL, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法) -
- upload?Task?With?Request:??from?File:??
: 通過HTTP請求發(fā)送指定文件給指定URL -
- upload?Task?With?Request:??from?File:completionHandler:
: 通過HTTP請求發(fā)送指定文件給指定URL, 在completionHandler中處理數(shù)據(jù). 該方法會繞過代理方法(除了身份認(rèn)證挑戰(zhàn)的代理方法) -
upload?Task?With?StreamedRequest
: 通過HTTP請求發(fā)送指定URLRequest數(shù)據(jù)流給指定URL
-
-
添加stream任務(wù)
-
- streamTask?With?HostName:port:??
: 通過給定的域名和端口建立雙向TCP/IP連接 -
- streamTask?With?NetService:
: 通過給定的network service建立雙向TCP/IP連接
-
-
管理session
-
finishTasksAndInvalidate
: 任務(wù)全部完成后銷毀session -
flushWithCompletionHandler:
: 清除硬盤上的cookies和證書, 清理暫時(shí)的緩存, 確保未來能響應(yīng)一個(gè)新的TCP請求 -
getTasksWithCompletionHandler:
: 異步調(diào)用session中所有upload, download, data tasks的completion回調(diào). -
invalidateAndCancel
: 取消所有未完成的任務(wù)并銷毀session -
resetWithCompletionHandler:
: 清空cookies, 緩存和證書存儲, 移除所有磁盤文件, 清理正在執(zhí)行的下載任務(wù), 確保未來能響應(yīng)一個(gè)新的socket請求
-
API總結(jié)
所有創(chuàng)建task的方法, 只要帶有completionHandler這個(gè)參數(shù)的, 均表示為請求過程中不會觸發(fā)代理方法. 所有不帶有completionHandler這個(gè)參數(shù)的, 均會走代理方法流程.
如果你實(shí)現(xiàn)了URLSession:?did?Receive?Challenge:?completion?Handler:?
方法又沒有在該方法調(diào)用completionHandler, 請求就會遭到阻塞
斷點(diǎn)續(xù)傳
- 下載失敗/暫停/被取消, 可以通過task的
- cancel?By?Producing?Resume?Data:?
方法保存已下載的數(shù)據(jù), 然后調(diào)用session的download?Task?With?Resume?Data:?
方法, 觸發(fā)代理的URLSession:?download?Task:?did?Resume?At?Offset:?expected?Total?Bytes:?
方法
Something else Important
NSCopying Behavior
session, task和configuration對象都支持copy操作 :
- session/task copy : 返回session對象本身
- configuration copy : 返回一個(gè)無法修改(immutable)的對象.
線程安全
URLSession 的API全部都是線程安全的. 你可以在任何線程上創(chuàng)建session和tasks, task會自動調(diào)度到合適的代理隊(duì)列中運(yùn)行.
Warning
后臺傳輸?shù)拇矸椒?code>URLSession?Did?Finish?Events?For?Background?URLSession:?可能會在其他線程中被調(diào)用. 在該方法中你應(yīng)該回到主線程然后調(diào)用completion handler去觸發(fā)AppDelegate中的
application:?handle?Events?For?Background?URLSession:?completion?Handler:?
方法.
常量
-
NSURLSession-Specific NSError user?Info Dictionary Keys
: NSURLSession API 中出現(xiàn)的NSError的userInfo的keys -
Background Task Cancellation reasons
: 指示系統(tǒng)為什么取消了你的后臺任務(wù)的理由 -
Transfer Size Constant
: 指示一個(gè)未知傳輸大小的常量
參考文檔
NSURLSession - Foundation
WWDC 2013 - Session 204 - What's New with Multitasking
WWDC 2013 - Session 705 - What's New in Foundation Networking
WWDC 2015 - Session 711 - Networking with NSURLSession
WWDC 2016 - Session 711 - NSURLSession: New Features and Best Practices