長期以來咱們在處理 iOS 中的網絡通訊的時候都是直接使用 OC 版 AFNetworking 或者 Swift 版 Alamofire ,可是咱們居然不多會去認真關注 iOS 中的網絡基礎底層內容。這同時折射出了 iOS 開發中的一個問題:iOS 開發有着豐富的組件、完善的生態、成熟的機制,這些特質讓 iOS 開發的門檻低的幾乎只要一臺 MBP,但這也讓開發人員思惟退化慢慢的變成了一名搬磚工。這篇文章將介紹 iOS 底層網絡通訊的基礎內容。程序員
從服務器獲取數據、更新我的資料、下載或者上傳文件,這些App中功能都是經過 HTTP 請求進行實現的。爲了方便開發者對 HTTP 進行處理,Apple爲 咱們提供了 URLSession 組件。URLSession 是 iOS7 以後引入的底層網絡通訊架構,在此以前使用的是 NSURLConnection(iOS9 中已廢棄)。其實 URLSession 除了指代同名類以外,更大程度上應該表達爲整套的網絡架構相關的類。URLSession 包含了 NSURLConnection 時代就有的 URLRequest 與 URLCache,可是它將 NSURLConnection 進行了分解。分解後的結構以下圖:編程
URLSessionDelegate 只負責處理 Session 級別的事務,諸如服務器信任,客戶端證書的評估。該 delegate 並非必須的,若是開發者沒有本身設置 delegate 系統會完成默認設置可是必須提供一個 completionHandler 來進行數據處理。緩存
另外一個須要注意的是:不一樣於咱們經常使用的編程規範,session 對 delegate 保持這強引用而不是 weak。這代表此處的代碼設計會涉及到內存泄漏的問題,因此咱們要當心處理。處理辦法是使用單例模式或者經過 finishTasksAndInvalidate() 、 invalidateAndCancel() 方法來使 session 失效,調用後者會馬上生效,而前者則會等待 session 明確完成或者失敗後纔會失效。至於這兩個方法的調用時機,你能夠在 URLSessionDelegate 或者 URLSessionDataDelegate 及其子類的某個方法中,也能夠在控制器的 viewWillDisappear 中調用。不過我建議使用後一種處理方式,由於一個控制器可能存在多個請求任務,若是每一個 Task 都銷燬 Session 也就代表同一個 Session 在每一個 Task 開始的時候都須要初始化,這不只致使代碼冗餘也下降了代碼效率。安全
URLSessionConfiguration 對象用於對 URLSession 對象進行初始化配置。這也是 URLSession 與 NSURLConnection 相比最明顯的改進之一,咱們能夠配置每一個 session 的緩存,協議,cookie,以及證書策略(credential policy),甚至跨程序共享這些信息。這將容許程序和網絡基礎框架之間相互獨立,不會發生干擾。服務器
URLSession 對象中的 configuration 屬性,實際上是在進行初始化時 URLSessionConfiguration 對象的拷貝,而且該屬性爲只讀屬性。也就是說每一個 URLSession 對象只在初始化時配置 configuration,以後都不會發生改變。cookie
URLSessionConfiguration 有三類工廠方法:網絡
default:返回標準的 configuration,使用了全局的磁盤緩存(除了文件下載任務外)、鑰匙串中的證書、Cookies。session
ephemeral:相似於default,可是全部的數據都存儲在內存中,不會對緩存、Cookie 和證書進行持久化存儲。能夠將這個配置看做是私有 session,對於實現像祕密瀏覽功能來講是很是理想的。閉包
background:該配置會建立一個後臺 session。後臺 session 不一樣於常規狀況,它甚至能夠在應用程序掛起,退出或者崩潰的狀況下運行上傳、下載任務。架構
URLSessionConfiguration 還有如:超時時間、緩存策略、Cookie 策略、安全策略等屬性的設置,具體的配置選項能夠自行查看文檔。
URLSessionTask 是一個抽象類,它表示一次網絡任務。URLSession 經過建立不一樣的 URLSessionTask 對象來處理各類不一樣的網絡請求任務,因此 URLSessionTask 有多個類型的子類:
URLSessionDataTask:該類用於處理 HTTP 中 GET、POST 方法獲取的數據
URLSessionUploadTask:該類用於處理 HTTP 中 POST、PUT 方法上傳數據到服務器
URLSessionDownloadTask:該類用於處理從服務器下載文件的網絡任務
URLSessionStreamTask:該類用於處理 TCP/IP 鏈接的網絡任務(新增的類型,未使用過。猜想用於視頻、IM 類應用)
全部這些任務均可以掛起、開始、取消,下載任務甚至能夠實現斷點續傳。這些 task 得到的數據的處理方式能夠經過 completionHandler 閉包或者 delegate 中的方法,可是兩者取其一。
Data task 能夠經過 URL 或 URLRequest 建立(使用前者至關因而使用一個對於該 URL 進行標準 GET 請求的 URLRequest,這是一種快捷方法)。下面示例爲從 itunes 中查詢某個關鍵詞的歌曲:
let expectedCharSet = CharacterSet.urlQueryAllowed let searchTerm = searchBar.text!.addingPercentEncoding(withAllowedCharacters: expectedCharSet)! let defaultSession = URLSession.shared let url = URL(string: "https://itunes.apple.com/search?media=music&entity=song&term=\(searchTerm)") dataTask = defaultSession.dataTask(with: url!, completionHandler: { data, response, error in ... }) dataTask?.resume()
上傳、下載文件的代碼與上面的基本同樣,除了新建 dataTask 的類型不一樣。
整體來講蘋果對 URLSession 體系的設計這套體系清晰、簡潔、高效,也是咱們在平常編碼過程須要認真學習的。做爲 iOS 程序員除了努力搬磚外,更應該認真對待這些設計思想,不要成爲依靠 cocoapods 生存的浮萍。因此在使用輪子的時候,必定不能忘了構建輪子的基本知識,這些基礎纔是程序員生根的關鍵。iOS 只不過是代表了當前咱們專一的領域,而程序員纔是咱們真正的職業。