此文章為引用,原文鏈接:http://www.itdecent.cn/p/2501a618ad1b
一、首先聊一聊這些年蘋果爸爸對(duì)網(wǎng)絡(luò)層的改變
1、在2003年隨著第一版Safari的發(fā)布就發(fā)布了NSURLConnection。 作為網(wǎng)絡(luò)基礎(chǔ)架構(gòu),這些年也服務(wù)了成千上萬(wàn)的iOS和Mac OS程序,也做得相當(dāng)?shù)牟诲e(cuò)。
2、2013年蘋果推出iOS 7,這個(gè)版本的iOS被稱為革命性的iOS,而我們以前所用到的NSURLConnection這個(gè)網(wǎng)絡(luò)庫(kù)也被蘋果爸爸給重構(gòu), 并且重新命名為NSURLSession。
3、2014年的iOS 8蘋果爸爸宣布正式淘汰NSURLConnection,同時(shí)發(fā)布了App Extensions。
4、2015年iOS 9蘋果爸爸讓網(wǎng)絡(luò)變得更加安全了。
(1)App Transport Security (ATS):核心目的是防止意外泄露用戶的敏感數(shù)據(jù),ATS加強(qiáng)了NSURLSession的默認(rèn)策略,現(xiàn)在的NSURLSession不允許明文的HTTP加載,他只會(huì)使用HTTPS連接。
(2)NSURLSession支持HTTP/2協(xié)議:如果已經(jīng)在程序中使用NSURLSession,所有的這些都會(huì)自動(dòng)轉(zhuǎn)換。HTTP/2協(xié)議已經(jīng)無(wú)縫集成到NSURLSession的API中,不需要修改任何代碼工程就可支持HTTP/2協(xié)議。
(3)watchOS 支持NSURLSession:之前iWatch通過藍(lán)牙和iphone連接,iphone下載完成在通過藍(lán)牙傳到watch?,F(xiàn)在watch可以通過使用NSURLSession自己下載。
(4)共享cookies:iOS8推出了App Extension,之前App與其Extension都默認(rèn)對(duì)數(shù)據(jù)的持有進(jìn)行獨(dú)立處理,就像放在兩個(gè)不同的數(shù)據(jù)集合里,而現(xiàn)在可以讓App和其Extension共享同一個(gè)數(shù)據(jù)集合。具體代碼如下:

(5)增加NSURLSessionStreamTask:以前我們使用NSInputStream/NSOutputStream來進(jìn)行一些非HTTP的連接, 例如利用TCP連接一臺(tái)遠(yuǎn)程的服務(wù)器等等, 現(xiàn)在我們有了NSURLSessionStreamTask讓我們更簡(jiǎn)單地實(shí)現(xiàn)以上功能。
6、2016年 iOS 10新增NSURLSessionTaskMetrics和NSURLSessionTaskTransactionMetrics:對(duì)發(fā)送請(qǐng)求/DNS查詢/TLS握手/請(qǐng)求響應(yīng)等各種環(huán)節(jié)時(shí)間上的統(tǒng)計(jì)。更易于我們檢測(cè), 分析我們的請(qǐng)求緩慢到底是發(fā)生在哪個(gè)環(huán)節(jié),并對(duì)此進(jìn)行優(yōu)化提升我們APP的性能。
7、2017年iOS 11蘋果爸爸在網(wǎng)絡(luò)層做了新增和優(yōu)化了。
(1)提供了NSProgressReporting協(xié)議,且NSURLSessionTask實(shí)現(xiàn)了這個(gè)協(xié)議,讓我們能夠獲得progress對(duì)象,這個(gè)progress對(duì)象可以以0~1.0的方式告訴你當(dāng)前進(jìn)度,而不用你自己去拿到已獲得的數(shù)據(jù)量去除以需要獲得的數(shù)據(jù)總量從而得出進(jìn)度。然后這個(gè)progress對(duì)象跟NSURLSessionTask的綁定是雙向的:你調(diào)用progress對(duì)象的cancel、pause、resume也會(huì)使得task變?yōu)閏ancel、pause、resume,反之亦然。
(2)新增waitsForConnectivity屬性,以前進(jìn)行網(wǎng)絡(luò)調(diào)用時(shí),如果網(wǎng)絡(luò)不通,那么系統(tǒng)就會(huì)報(bào)個(gè)錯(cuò)告訴你網(wǎng)絡(luò)不通。這時(shí)候你要么輪詢要么讓用戶手動(dòng)retry,然后網(wǎng)絡(luò)通了請(qǐng)求才能發(fā)送出去?,F(xiàn)在只需要把NSURLSessionConfiguration的waitsForConnectivity設(shè)置成YES,這樣如果請(qǐng)求發(fā)送的時(shí)候網(wǎng)絡(luò)不通,那么這個(gè)請(qǐng)求就會(huì)等到網(wǎng)絡(luò)通了的時(shí)候再發(fā)出去。
(3)在NSURLSessionTask的delegate里面新增了一個(gè)方法urlSession:task:willBeginDelayedRequest:completionHandler:系統(tǒng)在發(fā)起請(qǐng)求之前會(huì)調(diào)一個(gè)這個(gè)回調(diào),然后在這個(gè)completionHandler里面你告訴系統(tǒng)這個(gè)請(qǐng)求是否要發(fā)出去,是否要修改。(因?yàn)閯?chuàng)建的后臺(tái)請(qǐng)求在還沒發(fā)出去的時(shí)候可能因?yàn)樯舷挛淖兓脑驅(qū)е逻@個(gè)請(qǐng)求無(wú)意義)
(4)earliestBeginDate屬性,在后臺(tái)請(qǐng)求的時(shí)候以前系統(tǒng)不知道什么時(shí)候去發(fā)起你的請(qǐng)求才是最合適的 ,現(xiàn)在給task設(shè)置一個(gè)earliestBeginDate,系統(tǒng)在這之前是不會(huì)發(fā)起請(qǐng)求的。
(5)iOS 11可以通過設(shè)置NSURLSessionTask的countOfBytesClientExpectsToSend和countOfBytesClientExpectsToReceive來讓系統(tǒng)更好地調(diào)度你的后臺(tái)網(wǎng)絡(luò)任務(wù)。
(6)multipathServiceType:移動(dòng)設(shè)備多路協(xié)議,這使得移動(dòng)設(shè)備的TCP包可以在這兩個(gè)(多個(gè))鏈路上隨意切換著發(fā)(同時(shí)開啟兩個(gè)流量鏈路),而不必?cái)嗑€重連。
(7)iOS 11支持ECN(顯式擁塞通知)可以最大化的使用網(wǎng)絡(luò)帶寬,減少包的重發(fā)次數(shù),降低延遲。還有iOS 11里的網(wǎng)絡(luò)操作被移動(dòng)到User Space去了。iOS11支持Brotli壓縮算法。iOS11更新了Public Suffix List。
8、未來會(huì)有哪些變化
(1)TLS1.3:蘋果要把網(wǎng)絡(luò)庫(kù)整體遷移到支持TLS1.3,年底TLS1.3的標(biāo)準(zhǔn)應(yīng)該能出來。現(xiàn)在基于TLS1.3草稿的實(shí)現(xiàn)可以弄下來自己測(cè)試著玩了。最新的TLS1.3草稿已經(jīng)出到21了:draft-ietf-tls-tls13-21。
(2)QUIC:Google搞了個(gè)QUIC,蘋果在跟進(jìn)。QUIC可以理解成UDP實(shí)現(xiàn)的TCP+TLS+HTTP/2集合體。主要是提高了數(shù)據(jù)傳輸效率和鏈接效率。目前QUIC的開發(fā)才剛剛開始,項(xiàng)目網(wǎng)站提供了玩具客戶端和玩具服務(wù)端給大家玩:Playing with QUIC。
二、聊一聊NSURLSession
1、支持data, ftp, http(s)協(xié)議, 同時(shí)支持代理服務(wù)器和socks網(wǎng)關(guān).
2、支持http/1.1, http/2, spdy協(xié)議, 但同時(shí)需要服務(wù)器支持ALPN和NPN.
3、ALPN(Application Layer Protocol Negotiation,應(yīng)用層協(xié)議協(xié)商)
4、NPN(Next Protocol Negotiation,下一代協(xié)議協(xié)商)
5、NPN是服務(wù)端發(fā)送它支持的HTTP協(xié)議列表, 供客戶端選擇; 而ALPN則相反,由客戶端發(fā)送它支持的HTTP協(xié)議列表, 供服務(wù)端選擇。如果缺少NPN/ALPN其中一個(gè), 則無(wú)法使用HTTP/2通信。
想詳細(xì)了解HTTP/2的可以參考這兩篇文章為什么我們應(yīng)該盡快支持 ALPN和談?wù)?HTTP/2 的協(xié)議協(xié)商機(jī)制
6、NSURLSession相關(guān)類為 :
? ? ?? NSURLSession
? ? ?? NSURLSessionConfiguration
? ? ?? NSURLSessionDelegate
? ? ?? NSURLSessionTask
? ? ?? NSURLSessionTaskMetrics
? ? ?? NSURLSessionTaskTransactionMetrics
用一個(gè)簡(jiǎn)單的圖來表示一下他們各個(gè)類之間的關(guān)系:

(一)同名類NSURLSession
初始化方式:
? 1、 [NSURLSession sharedSession];全局單例session,有一定的局限性。
? 2、自定義配置文件,設(shè)置代理
?? [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
? ? [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
3、后臺(tái)session(由NSURLSessionConfiguration)配置。
(二)NSURLSessionConfiguration
NSURLSessionConfiguration 有三個(gè)類方法,這很好地說明了 NSURLSession 設(shè)計(jì)時(shí)所考慮的不同的使用場(chǎng)景。
1、+defaultSessionConfiguration 返回一個(gè)標(biāo)準(zhǔn)的 configuration,共享 NSHTTPCookieStorage,共享 NSURLCache 和共享 NSURLCredentialStorage。
2、+ephemeralSessionConfiguration 返回一個(gè)預(yù)設(shè)配置,這個(gè)配置中不會(huì)對(duì)緩存,Cookie 和證書進(jìn)行持久性的存儲(chǔ)。這對(duì)于實(shí)現(xiàn)像秘密瀏覽這種功能來說是很理想的。
3、+backgroundSessionConfiguration:(NSString *)identifier 創(chuàng)建一個(gè)后臺(tái) session。后臺(tái) session 不同于常規(guī)的,普通的 session,它甚至可以在應(yīng)用程序掛起,退出或者崩潰的情況下運(yùn)行上傳和下載任務(wù)。
NSURLSessionConfiguration擁有20多個(gè)配置屬性:
1、基本配置
(1)HTTPAdditionalHeaders 指定了一組默認(rèn)的可以設(shè)置出站請(qǐng)求的數(shù)據(jù)頭。這對(duì)于跨 session 共享信息,如內(nèi)容類型,語(yǔ)言,用戶代理和身份認(rèn)證,是很有用的。

(2)networkServiceType 對(duì)標(biāo)準(zhǔn)的網(wǎng)絡(luò)流量,網(wǎng)絡(luò)電話,語(yǔ)音,視頻,以及由一個(gè)后臺(tái)進(jìn)程使用的流量進(jìn)行了區(qū)分。
(3)allowsCellularAccess 和 discretionary 被用于節(jié)省通過蜂窩網(wǎng)絡(luò)連接的帶寬。對(duì)于后臺(tái)傳輸?shù)那闆r,推薦大家使用 discretionary 這個(gè)屬性,因?yàn)閍llowsCellularAccess會(huì)把 WiFi 和電源的可用性考慮在內(nèi)。
(4)timeoutIntervalForRequest 和 timeoutIntervalForResource 分別指定了對(duì)于請(qǐng)求和資源的超時(shí)間隔。
(5)HTTPMaximumConnectionsPerHost可以在需要時(shí)限制連接到特定主機(jī)的數(shù)量。
(6)sessionSendsLaunchEvents 指定該 session 是否應(yīng)該從后臺(tái)啟動(dòng)。
(7)connectionProxyDictionary 指定了 session 連接中的代理服務(wù)器。
(8)waitsForConnectivity如果請(qǐng)求發(fā)送的時(shí)候網(wǎng)絡(luò)不通,那么這個(gè)請(qǐng)求就會(huì)等到網(wǎng)絡(luò)通了的時(shí)候再發(fā)出去。
(9)multipathServiceType多路多協(xié)議網(wǎng)絡(luò)操作這使得移動(dòng)設(shè)備的TCP包可以在這兩個(gè)(多個(gè))鏈路上隨意切換著發(fā)(同時(shí)開啟兩個(gè)流量鏈路),而不必?cái)嗑€重連。效果就是:Wi-Fi和Cellular可以共存,相互輔助。

(10)NSURLSessionMultipathServiceTypeHandover(可靠模式)
(11)這種模式下優(yōu)先考慮的是鏈接的可靠性。只有在Wi-Fi信號(hào)不好的時(shí)候,流量才會(huì)走Cellular。如果Wi-Fi信號(hào)好,但是Wi-Fi很慢,這時(shí)候也不會(huì)切到Cellular鏈路。
(12)NSURLSessionMultipathServiceTypeInteractive(低延時(shí)模式)
(13)這種模式下優(yōu)先考慮的是鏈接的低延時(shí)。系統(tǒng)會(huì)看Wi-Fi快還是Cellular快。如果Cellular比Wi-Fi快,哪怕此時(shí)Wi-Fi信號(hào)很好,系統(tǒng)也會(huì)把流量切到Cellular鏈路。
(14)NSURLSessionMultipathServiceTypeAggregate(混合模式)
(15)在這種模式下,Wi-Fi和Cellular會(huì)同時(shí)起作用。如果Wi-Fi是1G帶寬,Cellular也是1G帶寬,那么你的設(shè)備就能享受2G帶寬。(不能用于生產(chǎn)環(huán)境)
(16)需要注意的是,Multipath Protocols for Mobile Devices這個(gè)功能同時(shí)也需要服務(wù)端支持MPTCP(Multipath TCP)才行,如果服務(wù)端不支持的話,光客戶端支持沒用。linux起了一個(gè)項(xiàng)目在做這個(gè)事情,項(xiàng)目地址:https://multipath-tcp.org。有興趣的同學(xué)可以自己去看一下。
2、Cookie策略
HTTPCookieStorage存儲(chǔ)了session所使用的cookie。兩種初始化方式
(1)[NSHTTPCookieStorage sharedHTTPCookieStorage];
(2)[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:@"identifier"];iOS 9新增。
(3)NSHTTPCookieAcceptPolicy決定了什么情況下 session 應(yīng)該接受從服務(wù)器發(fā)出的 cookie。

3、安全策略
(1)URLCredentialStorage存儲(chǔ)了NSURLSession所使用的證書,默認(rèn)使用+sharedCredentialStorage單例對(duì)象。
(2)TLSMinimumSupportedProtocol和TLSMaximumSupportedProtocol確定session是否支持SSL協(xié)議。
4、緩存策略
(1)URLCache是 session 使用的緩存。默認(rèn)情況下會(huì)使用 NSURLCache 的 +sharedURLCache 這個(gè)單例對(duì)象。
(2)requestCachePolicy 指定了一個(gè)請(qǐng)求的緩存響應(yīng)應(yīng)該在什么時(shí)候返回。
5、自定義協(xié)議
(1)protocolClasses 用來配置特定某個(gè) session 所使用的自定義協(xié)議(該協(xié)議是 NSURLProtocol 的子類)的數(shù)組。
(三)NSURLSessionDelegate

session管理的一組tasks共享一個(gè)代理, 不想實(shí)現(xiàn)代理方法時(shí), 代理傳nil即可。代理協(xié)議分為 :
(1)NSURLSessionDelegate : session-level的代理方法。
(2)NSURLSessionTaskDelegate : task-level面向all的代理方法。
(3)NSURLSessionDataDelegate : task-level面向data和upload的代理方法。
(4)NSURLSessionDownloadDelegate : task-level的面向download的代理方法。
(5)NSURLSessionStreamDelegate : task-level的面向stream的代理方法。
(四)NSURLSessionTask

當(dāng)一個(gè) NSURLSessionDataTask 完成時(shí),它會(huì)帶有相關(guān)聯(lián)的數(shù)據(jù),一般來說,服務(wù)端對(duì)于一個(gè)上傳任務(wù)的響應(yīng)也會(huì)有相關(guān)數(shù)據(jù)返回,所以 NSURLSessionUploadTask 繼承自 NSURLSessionDataTask。
task 是由一個(gè) NSURLSession 創(chuàng)建的。每個(gè) task 的構(gòu)造方法都對(duì)應(yīng)有或者沒有 completionHandler 這個(gè) block 的兩個(gè)版本,例如:有這樣兩個(gè)構(gòu)造方法 –dataTaskWithRequest: 和 –dataTaskWithRequest:completionHandler:。
(1)NSURLSessionTask : Task的抽象基類。
(2)NSURLSessionDataTask : 以NSData的形式接收一個(gè)URLRequest的內(nèi)容。
(3)NSURLSessionUploadTask : 上傳NSData或者本地磁盤中的文件, 完成后以NSData的形式接收一個(gè)URLRequest的響應(yīng)。
(4)NSURLSessionDownloadTask : 下載完成后返回臨時(shí)文件在本地磁盤的URL路徑。
(5)NSURLSessionStreamTask : 用于建立一個(gè)TCP/IP連接。
以前我們使用NSInputStream/NSOutputStream來進(jìn)行一些非HTTP的連接, 例如利用TCP連接一臺(tái)遠(yuǎn)程的服務(wù)器等等, 現(xiàn)在我們有了NSURLSessionStreamTask讓我們更簡(jiǎn)單地實(shí)現(xiàn)以上功能。
NSURLSessionStreamTask的特性 :
(1)更輕松地使用TCP進(jìn)行通信。
(2)替代NSInputStream/NSOutputStream, 提供更優(yōu)的API。
(3)異步讀寫API。
(4)能自動(dòng)通過HTTP代理, 連接一個(gè)遠(yuǎn)程服務(wù)器。
(5)輕松轉(zhuǎn)換成NSStream。
(五)NSURLSessionTaskMetrics 和 NSURLSessionTaskTransactionMetrics
對(duì)發(fā)送請(qǐng)求/DNS查詢/TLS握手/請(qǐng)求響應(yīng)等各種環(huán)節(jié)時(shí)間上的統(tǒng)計(jì)。更易于我們檢測(cè),分析我們App的請(qǐng)求緩慢到底是發(fā)生在哪個(gè)環(huán)節(jié),并對(duì)此進(jìn)行優(yōu)化提升我們APP的性能。
NSURLSessionTaskMetrics對(duì)象與NSURLSessionTask對(duì)象一一對(duì)應(yīng)。每個(gè)NSURLSessionTaskMetrics對(duì)象內(nèi)有3個(gè)屬性 :
(1)taskInterval : task從開始到結(jié)束總共用的時(shí)間
(2)redirectCount : task重定向的次數(shù)
(3)transactionMetrics : 一個(gè)task從發(fā)出請(qǐng)求到收到數(shù)據(jù)過程中派生出的每個(gè)子請(qǐng)求, 它是一個(gè)裝著許多NSURLSessionTaskTransactionMetrics對(duì)象的數(shù)組。每個(gè)對(duì)象都代表下圖的一個(gè)子
API很簡(jiǎn)單,就一個(gè)方法 : - (void)URLSession: task: didFinishCollectingMetrics:, 當(dāng)收集完成的時(shí)候就會(huì)調(diào)用該方法。

fetchStart : 開始發(fā)起請(qǐng)求.
domainLookupStart : 發(fā)送DNS請(qǐng)求, 域名->IP地址
domainLookupEnd : DNS請(qǐng)求完成, 拿到IP地址
connectStart : 與遠(yuǎn)程服務(wù)器開始建立TCP連接
secureConnectionStart : HTTPS的TLS握手開始
secureConnectionEnd : HTTPS的TLS握手完成connectEnd : 與服務(wù)器建立起了TCP連接
requestStart : 開始傳輸HTTP header第一個(gè)字節(jié)的時(shí)間(遠(yuǎn)程/緩存)
requestEnd : HTTP最后一個(gè)字節(jié)傳輸完成的時(shí)間(遠(yuǎn)程/緩存)
responseStart : 從服務(wù)器得到數(shù)據(jù)(遠(yuǎn)程/緩存)
responseEnd : 從服務(wù)器接受完最后一個(gè)字節(jié)的數(shù)據(jù)(遠(yuǎn)程/緩存)
(六)NSSession的整個(gè)工作流程

(1)身份驗(yàn)證或TLS握手:
? ? ? ? 這是所有task都必須經(jīng)歷的一個(gè)過程. 當(dāng)一個(gè)服務(wù)器請(qǐng)求身份驗(yàn)證或TLS握手期間需要提供證書的話會(huì)調(diào)用這個(gè)代理。另外, 如果連接途中收到服務(wù)器返回需要身份認(rèn)證的response, 也會(huì)調(diào)用這個(gè)代理方法。

(2)重定位response:
? ? ? ? 如果response是HTTP重定位, session會(huì)調(diào)用下面的代理,這里需要調(diào)用completionHandler告訴session是否允許重定位,或者重定位到另一個(gè)URL,或者傳nil表示重定位的響應(yīng)body有效并返回。如果代理沒有實(shí)現(xiàn)該方法,則允許重定位直到達(dá)到最大重定位次數(shù)。

(3)DataTask
? ? ? ? <1> 對(duì)于一個(gè)data task來說,session會(huì)調(diào)用代理決定是否將一個(gè)dataTask轉(zhuǎn)換成download task,然后調(diào)用completion回調(diào)繼續(xù)接收data或下載data。

? ? ? ?<2> 在服務(wù)器傳輸數(shù)據(jù)給客戶端期間, 代理會(huì)周期性地收到

? ? ? ?<3> session會(huì)調(diào)用下面代理詢問你的app是否允許緩存。 如果代理不實(shí)現(xiàn)這個(gè)方法的話,默認(rèn)使用session綁定的Configuration的緩存策略。

(4)DownloadTask
? ? ? ? ?<1>session先會(huì)調(diào)用代理方法。

? ? ? ? <2>在服務(wù)器傳輸數(shù)據(jù)給客戶端期間, 調(diào)用下面代理給用戶傳數(shù)據(jù)。

? ? ? ?<3>當(dāng)用戶暫停下載時(shí),調(diào)用cancelByProducingResumeData:給用戶傳已下好的數(shù)據(jù)。

? ? ? ?<4>如果用戶想要恢復(fù)下載,把剛剛的resumeData以參數(shù)的形式傳給downloadTaskWithResumeData:方法創(chuàng)建新的task繼續(xù)下載。
? ? ? ?<5>如果download task成功完成了,調(diào)用下面代理把臨時(shí)文件的URL路徑給你。此時(shí)你應(yīng)該在該代理方法返回以前讀取他的數(shù)據(jù)或者把文件持久化。
(5)UploadTask
? ? ? ? ?上傳數(shù)據(jù)去服務(wù)器期間, 代理會(huì)周期性收到URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:回調(diào)并獲得上傳進(jìn)度的報(bào)告。
(6)StreamTask
? ? ? ? 如果任務(wù)的數(shù)據(jù)是由一個(gè)stream發(fā)出的, session就會(huì)調(diào)用代理的URLSession:task:needNewBodyStream:方法去獲取一個(gè)NSInputStream對(duì)象并提供一個(gè)新請(qǐng)求的body data。
(7)task completion
? ? ? ? 任何task完成的時(shí)候, 都會(huì)調(diào)用URLSession:task:didCompleteWithError:方法,error有可能為nil(請(qǐng)求成功),不為nil(請(qǐng)求失敗)
(8)銷毀session
? ? ? ?如果你不再需要一個(gè)session了, 一定要調(diào)用它的invalidateAndCancel或finishTasksAndInvalidate方法來釋放session否則會(huì)造成內(nèi)存泄露。
(七)蘋果爸爸建議的最佳網(wǎng)絡(luò)實(shí)踐
1、IPv6
蘋果爸爸說:IPv6各種好,大家快來用。如果你不支持IPv6,爸爸就不讓你上架。要支持IPv6的話,老老實(shí)實(shí)用NSURLSession或者CFNetwork就OK了。
不要做的事情:
(1)不用歷史遺留的IPv4 API。
(2)不要直接用IPv4的地址做鏈接,應(yīng)該用域名去做請(qǐng)求。
(3)發(fā)包前不要做各種檢查:比如你在建立鏈接之前想看一下我當(dāng)前這個(gè)設(shè)備是不是IPv4的地址,這種做法就不行。
(4)不要直接使用socket去發(fā)起請(qǐng)求。
2、不要引入其他的網(wǎng)絡(luò)庫(kù),要使用蘋果自己的API
? ? ?蘋果并不是在說AFNetworking、Alamofire不能用。這些第三方庫(kù)本質(zhì)上還是基于NSURLSession,也就是蘋果的API去開發(fā)的。所以用它們沒問題。蘋果的意思是不希望你使用別的基于Socket開發(fā)的網(wǎng)絡(luò)庫(kù),例如:ACE、Asio這些。
3、一般來說一個(gè)App就一個(gè)NSURLSession就夠了
? ? ?以前遷移NSURLConnection到NSURLSession的時(shí)候,有人每次都創(chuàng)建新的NSURLSession,但事實(shí)上這是沒必要的。各個(gè)并行的NSURLSessionTask可以共享同一個(gè)NSURLSession。如果你使用了多個(gè)NSURLSession的話,記得清理就好,不清理是會(huì)產(chǎn)生內(nèi)存泄漏的。
4、NSURLSession的delegate方法和block方法不要同時(shí)使用
? ? ?如果你用了block,那么delegate就不會(huì)回調(diào)了。這事情僅有兩個(gè)特例是兩個(gè)都回調(diào)的:taskIsWaitingForConnectivity和didReceiveAuthenticateChallenge。
三、了解一下Network Extension Framework
iOS 9 發(fā)布之后,推出NetworkExtension, 它可給系統(tǒng)WiFi列表列表里邊的WiFi設(shè)置密碼 、標(biāo)簽(副標(biāo)題) ?來直接點(diǎn)擊連接。 還可獲取整個(gè)WiFi列表,建立VPN等。
1、iOS 11新增了兩個(gè)類:NEHotSpotConfiguration,NEDNSProxyProvider。
(1)NEHotSpotConfiguration
? ? ? ? NEHotSpotConfiguration可以讓你的智能設(shè)備在鏈接手機(jī)App之后,能夠很方便地通過在手機(jī)App上的操作來實(shí)現(xiàn)熱點(diǎn)的鏈接。例如你買了一個(gè)網(wǎng)絡(luò)攝像頭,你想要連上攝像頭的Wi-Fi熱點(diǎn)去配置這個(gè)攝像頭的話,以前要這么操作:

現(xiàn)在用NEHotSpotConfiguration就能很方便地搞定事情了:

當(dāng)然,這套API也可以被拿來模擬各種網(wǎng)絡(luò)環(huán)境,在測(cè)試App的時(shí)候很有用。
(2)NEDNSProxyProvider
NEDNSProxyProvider可以用來設(shè)置你的手機(jī)如何跟DNS做交互。你可以自己發(fā)DNS請(qǐng)求,也可以自己基于不同的協(xié)議去做DNS查詢。例如DNS over TLS,DNS over HTTP。