OC之NSURLSessionTask

NSURLSessionTask 是對網絡會話的管理者 NSURLSession 創(chuàng)建任務的封裝,它僅僅是個抽象的基類,實際使用中可以劃分為不同的任務:

  • NSURLSessionDataTask:數據任務杉女,使用NSData對象發(fā)送和接收數據;數據任務旨在向服務器發(fā)出簡短的阿逃,經常是交互式的請求逸绎;支持默認會話骡男、臨時會話淆游,但不支持后臺會話;
    通過對代理方法 -URLSession:dataTask:didReceiveData: 的一系列調用來接收資源隔盛;該任務供使用者立即解析犹菱。
  • NSURLSessionUploadTask :上傳任務,與數據任務相似骚亿,但是它們還發(fā)送數據(通常以文件形式)已亥,并在應用程序不運行時支持后臺上傳;
    通過引用要上傳的文件或數據對象来屠,或利用 -URLSession:task:needNewBodyStream: 來提供上傳主體顯式創(chuàng)建的虑椎;與數據任務的區(qū)別在于實例構造方式不同震鹉!
  • NSURLSessionDownloadTask :下載任務,直接將響應數據寫入臨時文件捆姜,任何類型的會話都支持下載和上傳任務传趾。
    任務完成后,delegate 調用 -URLSession:downloadTask:didFinishDownloadingToURL: 在適當時機將該文件移動到沙盒的永久位置泥技、或者讀取該文件浆兰;
    如果取消任務,NSURLSessionDownloadTask 可以生成一個 data blob珊豹,用于稍后恢復下載簸呈。
  • NSURLSessionWebSocketTaskWebSocket任務,使用 RFC 6455 中定義的WebSocket協議通過TCP和TLS交換消息店茶。
  • NSURLSessionStreamTask:從 iOS9 開始支持該任務蜕便,這允許TCP/IP連接到指定的主機和可選的安全握手和代理導航的端口;
NSURLSessionTask.png

通過NSURLSession 創(chuàng)建任務贩幻,有兩種響應方式:

  • 設置 delegate:響應報文被 NSURLSessionDelegate 的代理方法處理轿腺;
  • 使用 completionHandler 創(chuàng)建任務,那么在 completionHandler 中處理響應數據(即使設置了 delegate)丛楚;

如果設置了delegate族壳,根據不通的任務,由不同的 NSURLSessionDelegate 方法來處理:

  • NSURLSessionDelegate : 是 session 級別的協議趣些,主要管理 session 的生命周期仿荆、處理證書認證等
  • NSURLSessionTaskDelegate : 是 task 級別的協議,面向所有的委托方法
  • NSURLSessionDataDelegate : 是 task 級別的協議坏平,主要用來處理 data 和 upload赖歌,如接收到響應,接收到數據功茴,是否緩存數據
  • NSURLSession?Download?Delegate : 是 task 級別的協議,用來處理下載任務
  • NSURLSessionStreamDelegate : 是 task 級別的協議孽亲,用來處理 streamTask
  • NSURLSessionWebSocketDelegate: 是 task 級別的委托坎穿,處理特定于 WebSocketTask 的事件
NSURLSessionDelegate.png

可以重復使用一個NSURLSession來創(chuàng)建多個任務,創(chuàng)建的 NSURLSessionTask 對象總是處于掛起狀態(tài)返劲,在它們執(zhí)行之前必須調用 -resume 方法玲昧。啟動任務之后NSURLSession對該任務持有強引用,直到任務完成或者失斃郝獭孵延!

1、NSURLSessionTask API

NSURLSessionTask 只能通過 NSURLSession的實例方法獲取亲配,不能使用-init尘应、+new 創(chuàng)建惶凝!

所有任務屬性都支持鍵值觀察!

1.1犬钢、獲取任務信息
/** 當前任務的請求對象
 * @note 通常與 originalRequest 相同苍鲜,除非服務器以重定向到不同URL的方式響應初始請求
*/
@property (nullable, readonly, copy) NSURLRequest  *currentRequest;

/** 創(chuàng)建任務時傳遞的原始請求對象;
 * 如果是一個streamTask玷犹,則可能為 nil
 * @note 通常與 currentRequest 相同混滔,除非服務器以重定向到不同URL的方式響應初始請求
*/
@property (nullable, readonly, copy) NSURLRequest  *originalRequest;

/** 服務器對 currentRequest 的響應信息
 * 包含關于服務器提供的請求信息,此信息始終包含originalRequest歹颓;它還可能包含預期的數據長度坯屿、MIME類型信息、編碼信息巍扛、建議的文件名等领跛;
 * @note 如果沒有收到服務器的回應,可能為 nil
 */
@property (nullable, readonly, copy) NSURLResponse *response;
 
/** 該任務的標識符电湘,由所屬的 NSURLSession 實例分配隔节,且具有唯一性
 * @note 在不同 NSURLSession 中的任務,可能具有相同的 taskIdentifier 寂呛;
 */
@property (readonly) NSUInteger taskIdentifier;

/** 開發(fā)人員為任務提供的描述怎诫,可用于調試程序、追蹤任務贷痪、或直接顯示給用戶幻妓!
 * @note 系統(tǒng)不會設置該值,可能是 nil劫拢;
 */
@property (nullable, copy) NSString *taskDescription;

/** 任務失敗的錯誤信息
 * 如果有錯誤肉津,由代理方法 -URLSession:task:didCompleteWithError 返回
 * 如果沒有錯誤,該值為 nil
*/
@property (nullable, readonly, copy) NSError *error;
1.2舱沧、任務進展
/** 任務進度 */
@property (readonly, strong) NSProgress *progress API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/** 響應數據的預期長度妹沙,通常在 HTTP 響應頭的 Content-Length 字段;
 * 如果響應頭沒有該字段熟吏,則此值為 NSURLSessionTransferSizeUnknown
 */
@property (readonly) int64_t countOfBytesExpectedToReceive;

/** 從服務器已接收到的body字節(jié)數
 * 沒有body預期距糖,字節(jié)數可能是零;
 * 如果不知道字節(jié)數牵寺,值為 NSURLSessionTransferSizeUnknown悍引;
 * @note 如果需要監(jiān)測該值的變化,需要實現某個代理方法:
 *  <li> 用于上傳任務帽氓,實現 -URLSession:dataTask:didReceiveData: 方法
 *  <li> 用于下載任務趣斤,實現 -URLSession:downloadTask:didWriteData:totalBytesWritten:totalbytestowrite: 方法
 */
@property (readonly) int64_t countOfBytesReceived;

/** 請求體 requestBody 的預計長度,在 HTTP 請求頭的 Content-Length 字段設置
 * 可以通過三種方式預估請求體的長度:
 *  <1>數據對象 upload body 的長度
 *  <2>上傳任務(而不是下載任務) :從磁盤上獲取上傳文件主體的長度
 *  <3>從 NSURLRequest 對象中獲取 Content-Length
 *
 * @note 如果提供 stream 或 body data黎休,則值為NSURLSessionTransferSizeUnknown;
 *      如果不提供 stream 或 body data浓领,則值為0
 */
@property (readonly) int64_t countOfBytesExpectedToSend;

/** 已發(fā)送到服務器的 body 的字節(jié)數
 * 監(jiān)聽該值的改變玉凯,需要實現代理方法:
 *    -URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
 * @note 只統(tǒng)計請求體的字節(jié)數,不包括請求頭
 */
@property (readonly) int64_t countOfBytesSent;
1.3镊逝、調度任務
/** 客戶端通過該任務預計將發(fā)送或者接收的最大字節(jié)數
 * 設置該值應考慮 HTTP headers 和body 或者 body stream 的大凶嘲 ;
 * 如果未設定該值撑蒜,系統(tǒng)使用默認值 NSURLSessionTransferSizeUnknown歹啼;
 * 系統(tǒng)使用該值來優(yōu)化 UNSURLSessionTask 的調度,因此建議提供一個近似值座菠,而不是接受默認值狸眼。
*/
@property int64_t countOfBytesClientExpectsToSend API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
@property int64_t countOfBytesClientExpectsToReceive API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));

/** 設置網絡加載開始的最早時間
 * 該值并不能保證網絡加載將在指定時間開始,僅保證加載不會提前開始浴滴;如果未設置拓萌,則不使用啟動延遲。
 * 該值僅適用于從后臺NSURLSession創(chuàng)建的任務升略;其它類型會話創(chuàng)建的任務無效微王;
 */
@property (nullable, copy) NSDate *earliestBeginDate API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
1.4、控制任務狀態(tài)
/** 取消任務:正在執(zhí)行的任務品嚣、已經掛起的任務炕倘;
 *  該方法立即返回,將任務標記為被取消翰撑。
 *  當任務被標記為被取消時罩旋,代理方法 -URLSession:task:didCompleteWithError: 收到一個 NSURLErrorCancelled 的錯誤
*/
- (void)cancel;

/** 臨時掛起任務:會阻止 NSURLSession 繼續(xù)加載數據
 * 任務在被掛起時不會產生網絡流量,與任務關聯的超時計時器將被禁用 -> 不受超時限制眶诈;
 * 下載任務可以在稍后繼續(xù)傳輸數據涨醋,但其它任務必須重新開始  -resume ;
 * 可能仍有此任務的代理方法被調用逝撬,例如在掛起時收到的數據浴骂,但在 -resume 發(fā)送之前,不會再使用代理方法進行數據傳輸宪潮;
*/
- (void)suspend;

/** 恢復被掛起的任務
 * 剛初始化的任務處于掛起狀態(tài)靠闭,需要調用此方法來啟動任務
*/
- (void)resume;

/** 任務的當前狀態(tài)(活動的、掛起的坎炼、正在取消、完成)
 * <ul> NSURLSessionTaskState 的枚舉值
 *     <li> NSURLSessionTaskStateRunning 任務正在進行拦键,此時任務受限于 Configuration 中指定的請求和資源超時時間
 *     <li> NSURLSessionTaskStateSuspended 任務暫停谣光,在任務恢復之前,不會進行進一步的處理芬为;此時任務不受超時限制萄金;
 *     <li> NSURLSessionTaskStateCanceling 任務取消蟀悦;會話將收到代理方法 -URLSession:task:didCompleteWithError:
 *     <li>  NSURLSessionTaskStateCompleted 任務已經完成(沒有被取消),會話將不再收到代理方法氧敢;
 *           如果成功完成日戈,則屬性error為nil;否則提供錯誤信息孙乖。
 *  </ul>
 */
@property (readonly) NSURLSessionTaskState state;

/** 主機處理該任務的相對優(yōu)先級浙炼,指定為0.0(最低優(yōu)先級)和1.0(最高優(yōu)先級)之間的浮點值
 * @discussion 優(yōu)先級只提供一個提示,而不是任務執(zhí)行的硬性要求唯袄,并不保證性能弯屈;
 *      任務的優(yōu)先級可以在任何時候改變,但不是所有的網絡協議都支持這個;在這些情況下恋拷,將使用最后一個生效的優(yōu)先級资厉。
 * <ul> 系統(tǒng)提供的優(yōu)先級
 *     <li> NSURLSessionTaskPriorityDefault  默認優(yōu)先級,值為0.5蔬顾,用于任何未指定優(yōu)先級的任務宴偿;
 *     <li> NSURLSessionTaskPriorityLow 低優(yōu)先級,值高于最小值0诀豁,低于默認值
 *     <li> NSURLSessionTaskPriorityHigh 高優(yōu)先級窄刘,其值高于默認值,低于最大值 1.0
 *  </ul>
 * 除了系統(tǒng)提供的這個三優(yōu)先級且叁,還可以使用 0 ~ 1.0 之間的任何浮點值
*/
@property float priority API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

2都哭、數據任務NSURLSessionDataTask

NSURLSessionDataTask 數據任務:直接將下載的數據作為一個或多個NSData返回到應用程序的內存中;是NSURLSessionTask的一個子類逞带,在 NSURLSessionTask 基礎上不提供任何額外的功能欺矫,僅僅是詞義的區(qū)別。當使用數據任務:

  • body data 上傳期間展氓,NSURLSession 定期調用代理方法 -URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: 獲取狀態(tài)信息穆趴;
  • 在接收到初始響應后,NSURLSession 調用代理方法 -URLSession:dataTask:didReceiveResponse:completionHandler: 檢查狀態(tài)代碼和響應頭遇汞,并可選地將數據任務轉換為下載任務未妹;
  • 在數據傳輸過程中,NSURLSession 調用代理方法 -URLSession:dataTask:didReceiveData: 接收數據空入;
  • 完成后络它,NSURLSession 調用代理方法 -URLSession:dataTask:willCacheResponse:completionHandler: 確定是否應該緩存響應

3、上傳任務NSURLSessionUploadTask

NSURLSessionUploadTask 上傳任務:用于需要 request body 的 HTTP 請求歪赢,如 POST 或 PUT 化戳;它是數據任務 NSURLSessionDataTask 的一個子類,在 NSURLSessionDataTask 基礎上不提供任何額外的功能埋凯,與數據任務對比:

  • <li> 需要調用 NSURLSession 上的不同方法來創(chuàng)建上傳任務
  • <li> 如果服務器提供一個響應点楼,上傳任務將該響應作為一個或多個NSData對象返回到內存中扫尖。
  • <li> 與數據任務不同,支持在后臺上傳內容掠廓;
  • <li> NSURLSessionDataTask 的所有代理方法同樣適用于 NSURLSessionUploadTasks 换怖;

創(chuàng)建上傳任務時,需要提供一個URLRequest實例蟀瞧,該實例包含請求頭的某些字段沉颂,如 content-Typecontent-Disposition 等黄橘。

  • 在iOS中兆览,當在后臺會話創(chuàng)建上傳任務時,系統(tǒng)會將該待上傳文件復制到一個臨時位置塞关;
  • 在上傳過程中 NSURLSession 定期調用代理方法 -URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: 獲取狀態(tài)信息抬探;
  • 當請求的上傳階段結束時,該任務的行為類似于數據任務帆赢,調用代理方法來提供服務器的響應頭小压、狀態(tài)代碼、內容數據等椰于。

4怠益、下載任務NSURLSessionDownloadTask

NSURLSessionDownloadTask 下載任務:將遠程文件下載到本地;是NSURLSessionTask的一個子類瘾婿,在 NSURLSessionTask 基礎上提供新的功能蜻牢;

  • 下載任務直接將服務器的響應數據寫入臨時文件,當數據從服務器到達時偏陪,為用應程序提供進度更新抢呆;
  • 在后臺會話中使用下載任務時,即使應用程序處于掛起狀態(tài)或沒有運行笛谦,這些下載也會繼續(xù)抱虐。
  • 可以暫停(取消)下載任務并稍后恢復它們(假設服務器支持這樣做);還可以恢復由于網絡連接問題而失敗的下載饥脑。

使用下載任務時恳邀,delegate 會收到幾個對下載場景唯一的回調

  • 在下載期間,URLSession 定期調用 -URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: 方法
  • 下載完成后灶轰,URLSession 調用 -URLSession:downloadTask:didFinishDownloadingToURL: 方法谣沸; 在這個方法中,需要將臨時文件移動到應用程序的沙箱容器目錄中笋颤;
  • 下載失敗時乳附,URLSession 調用 -URLSession:task:didCompleteWithError: 方法獲取錯誤信息,例如無法解析主機名或無法連接到主機。
@interface NSURLSessionDownloadTask : NSURLSessionTask

/** 可以恢復下載的取消任務方法
 * @param completionHandler 任務取消后的回調
 *        如果允許取消的任務恢復下載许溅,在該回調中需要提供一個 resumeData;在恢復下載時秉版,系統(tǒng)將該 resumeData 傳遞給 NSURLSession 的 -downloadTaskWithResumeData: 或 -downloadTaskWithResumeData:completionHandler: 方法來創(chuàng)建一個新任務贤重,繼續(xù)它停止的地方的下載。
 *       需要指定一個分派隊列清焕,以便在其中執(zhí)行Handler
 *
 * 什么情況下才能繼續(xù)下載該任務呢并蝗?
 *  <li> 自第一次 request,資源一直沒有更改
 *  <li> 任務是 HTTP 或 HTTPS GET 請求
 *  <li> 服務器在響應中提供 ETag 或 Last-Modified 頭(或兩者都提供)
 *  <li> 服務器支持 byte-range 請求
 *  <li> 系統(tǒng)沒有因為磁盤空間而刪除臨時文件
 * 只有滿足上述條件秸妥,才能繼續(xù)下載該任務
*/
- (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler;

@end

5滚停、StreamTask

從 iOS9 開始支持 NSURLSessionStreamTask 任務,這允許TCP/IP連接到指定的主機和可選的安全握手和代理導航的端口粥惧;使用 NSURLSession 顯示創(chuàng)建該任務键畴!
NSURLSessionStreamTaskNSURLSessionTask 的一個子類,在 NSURLSessionTask 基礎上增加了額外的功能突雪。
NSURLSessionStreamTask 在串行隊列中執(zhí)行異步讀寫操作起惕,讀寫操作完后或者失敗時在delegateQueue 上調用 completionHandler。 調用 -captureStreams 方法創(chuàng)建 NSInputStreamNSOutputStream 實例咏删;所有未完成的讀寫在 streams 創(chuàng)建之前完成惹想。一旦 streams 被傳遞到 NSURLSessionStreamDelegate 的代理方法,任務就被認為完成督函,不再接收消息嘀粱;這些 streamsNSURLSession 分離。

5.1辰狡、讀寫數據
/** 異步地從 stream 中讀取字節(jié)锋叨,并在完成時調用 completionHandler
 * @param minBytes 要讀取的最小字節(jié)數
 * @param maxBytes 要讀取的最大字節(jié)數
 * @param timeout 讀取字節(jié)的超時時間:如果在指定的時間間隔內未完成讀取,則取消讀取搓译,并調用 completionHandler 返回錯誤悲柱;
 *                可以設置為 0 防止讀取超時;
 * @param completionHandler 讀取完成或失敗時在 delegateQueue 上調用
 *              param data 從 stream 讀取的數據
 *              param atEOF 是否到達文件結束(EOF)些己,以便不能讀取更多數據
 *              param error 失敗的原因豌鸡;如果讀取成功則為nil
 * @note 如果發(fā)生錯誤,任何未完成的讀取也將失敗段标,新的讀取請求將立即出錯涯冠。
*/
- (void)readDataOfMinLength:(NSUInteger)minBytes maxLength:(NSUInteger)maxBytes timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSData * _Nullable data, BOOL atEOF, NSError * _Nullable error))completionHandler;

/** 異步地指定的數據底層 Socket,并在完成時調用 completionHandler
 * @param data 待寫入的數據
 * @param timeout 寫入字節(jié)的超時時間:如果在指定的時間間隔內未完成寫入逼庞,則取消寫入蛇更,并調用 completionHandler 返回錯誤;
 *                可以設置為 0 防止寫入超時;
 * @param completionHandler 寫入完成或失敗時在 delegateQueue 上調用
 *
 * @note completionHandler 的調用并不保證已經接收到所有字節(jié)派任,只能保證所有的數據都已寫入到內核
*/
- (void)writeData:(NSData *)data timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSError * _Nullable error))completionHandler;
5.2砸逊、捕捉 StreamData
/** 完成在串行隊列中等待的讀寫操作,然后調用 -URLSession:streamTask:didBecomeInputStream:outputStream: 代理方法掌逛。
 * 在該代理方法中师逸,將認為任務已完成,不再接收任何代理消息豆混。
*/
- (void)captureStreams;
5.3篓像、關閉讀Socket、寫Socket
/** 完成隊列中的讀寫操作皿伺,然后關閉底層 Socket 的寫端
 * 在調用此方法后员辩,可以繼續(xù)讀取數據 -readDataOfMinLength:maxLength:timeout:completionHandler: 直到流到達文件末尾(EOF)為止
 * 但不能調用 -writeData:timeout:completionHandler: 否則發(fā)生錯誤。
*/
- (void)closeWrite;

/** 完成隊列中的讀寫操作鸵鸥,然后關閉底層 Socket 的讀端
 * 調用此方法后奠滑,可以繼續(xù)寫入數據 -writeData:timeout:completionHandler:
 * 但不能調用 -readDataOfMinLength:maxLength:timeout:completionHandler: 否則發(fā)生錯誤。
*/
- (void)closeRead;
5.4脂男、啟動和停止安全連接
/** 完成隊列中的的讀寫操作养叛,然后建立安全連接,加密 handshake
 * TLS認證回調通過 -URLSession:task:didReceiveChallenge:completionHandler:
 */
- (void)startSecureConnection;

/** 隊列中的讀寫操作完成后宰翅,干凈地關閉安全連接弃甥。
 * @warning 該方法已被廢棄
 */
- (void)stopSecureConnection API_DEPRECATED("TLS cannot be disabled once it is enabled", macos(10.9,10.15), ios(7.0,13.0), watchos(2.0,6.0), tvos(9.0,13.0));

6、WebSocket任務

NSURLSessionWebSocketTaskNSURLSessionTask的子類汁讼,以 WebSocket 框架的形式在TCP和TLS上提供了面向消息的傳輸協議淆攻,它遵循RFC 6455中定義的WebSocket協議。

一個 WebSocket 任務嘿架,客戶端也可以提供一個協議列表瓶珊,公布在WebSocket握手階段;旦握手成功完成耸彪,通過一個可選的 delegate 被通知伞芹。在握手完成之前,客戶端可以被調用來處理 HTTP 重定向或身份認證蝉娜。
WebSocket任務也支持 Cookie唱较,將cookie存儲到 NSURLSession 的cookie中,并將cookie附加到傳出的 HTTP handshake 請求中召川。

6.1南缓、封裝的消息體

封裝的一個 WebSocket 消息,該對象將被傳遞給 -send 調用荧呐,并將從 -receive 調用中傳遞

/** 創(chuàng)建的消息類型:Data 或 String
*/
typedef NS_ENUM(NSInteger, NSURLSessionWebSocketMessageType) {
    NSURLSessionWebSocketMessageTypeData = 0,
    NSURLSessionWebSocketMessageTypeString = 1,
} API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));

API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
@interface NSURLSessionWebSocketMessage : NSObject

/** 使用 data 創(chuàng)建消息
 * 此時屬性 string = nil
*/
- (instancetype)initWithData:(NSData *)data NS_DESIGNATED_INITIALIZER;

/** 使用 string 創(chuàng)建消息
 * 此時屬性 data = nil
*/
- (instancetype)initWithString:(NSString *)string NS_DESIGNATED_INITIALIZER;

@property (readonly) NSURLSessionWebSocketMessageType type;
@property (nullable, readonly, copy) NSData *data;
@property (nullable, readonly, copy) NSString *string;


- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

@end
6.2汉形、發(fā)送和接收數據

異步執(zhí)行讀寫操作纸镊,并允許發(fā)送和接收包含二進制幀和UTF-8編碼文本幀的消息;該任務會將握手完成前隊列中的讀寫操作將在握手成功后按順序執(zhí)行概疆;

/** 發(fā)送一個WebSocket消息
 * @param message 待發(fā)送的WebSocket消息
 * @param completionHandler 接收發(fā)送結果逗威,發(fā)送失敗返回 error ;發(fā)送成功則error=nil
 *        如果出現錯誤岔冀,任何未完成的工作也將失斺挚;
 * @note completionHandler的調用并不保證遠程端已經接收到所有字節(jié)楣颠,只是它們已經被寫入到內核。
*/
- (void)sendMessage:(NSURLSessionWebSocketMessage *)message completionHandler:(void (^)(NSError * _Nullable error))completionHandler;

/** 一旦消息的所有frames可用咐蚯,讀取一個WebSocket消息
 * @param completionHandler 讀取結果童漩,成功獲取message,失敗返回 error春锋;
 * @note 在緩沖frames時矫膨,如果達到了 maximumMessage ,則receiveMessage調用將出錯期奔,所有未完成的工作也將失敗侧馅,導致任務結束。
*/
- (void)receiveMessageWithCompletionHandler:(void (^)(NSURLSessionWebSocketMessage* _Nullable message, NSError * _Nullable error))completionHandler;

/** 在接收消息失敗之前緩沖的最大字節(jié)數
 * 該值包括連續(xù)幀中所有字節(jié)的總和呐萌,一旦任務達到這個限制馁痴,receive 就會失敗。
*/
@property NSInteger maximumMessageSize;

/** 從客戶端發(fā)送一個ping幀肺孤,帶有一個從服務器端點接收pong的閉包罗晕。
 * @param pongReceiveHandler 當客戶端收到來自服務器端點的pong時,該Block被調用赠堵;
 *          如果在接收服務器端點pong之前連接丟失或發(fā)生錯誤小渊,該Block被調用返回錯誤信息
 *      當發(fā)送多個ping時 ,pongReceiveHandler 將總是按照客戶端發(fā)送 ping 的順序被調用茫叭;
 *
 * @discussion Ping-pong  是一種數據傳輸技術酬屉,本質是一種數據緩沖的手段;同時利用客戶端揍愁、服務器兩個數據緩沖區(qū)達到數據連續(xù)傳輸的目的:
 *   客戶端不必等待服務器的處理結果呐萨,繼續(xù)執(zhí)行并將結果保存在ping路的緩存中;客戶端執(zhí)行到一定時刻吗垮,服務端處理完成將結果 保存在pong路中垛吗;
 *  這樣服務端模塊無需等待繼續(xù)執(zhí)行,客戶端也無需等待繼續(xù)執(zhí)行烁登,轉而將結果存儲在ping路怯屉;提高了處理效率蔚舀。
 *
 * 單個緩沖區(qū)得到的數據在傳輸和處理中很容易被覆蓋,而 Ping-pong  緩沖區(qū)的方式能夠總是保持一個緩沖區(qū)的數據被利用锨络,另一個緩沖去用于存儲數據赌躺;即兩個相同的對象作為緩沖區(qū)交替地被讀和 被寫。
*/
- (void)sendPingWithPongReceiveHandler:(void (^)(NSError* _Nullable error))pongReceiveHandler;
6.3羡儿、關閉連接
typedef NS_ENUM(NSInteger, NSURLSessionWebSocketCloseCode)
{
    NSURLSessionWebSocketCloseCodeInvalid =                             0,
    NSURLSessionWebSocketCloseCodeNormalClosure =                    1000,
    NSURLSessionWebSocketCloseCodeGoingAway =                        1001,
    NSURLSessionWebSocketCloseCodeProtocolError =                    1002,
    NSURLSessionWebSocketCloseCodeUnsupportedData =                  1003,
    NSURLSessionWebSocketCloseCodeNoStatusReceived =                 1005,
    NSURLSessionWebSocketCloseCodeAbnormalClosure =                  1006,
    NSURLSessionWebSocketCloseCodeInvalidFramePayloadData =          1007,
    NSURLSessionWebSocketCloseCodePolicyViolation =                  1008,
    NSURLSessionWebSocketCloseCodeMessageTooBig =                    1009,
    NSURLSessionWebSocketCloseCodeMandatoryExtensionMissing =        1010,
    NSURLSessionWebSocketCloseCodeInternalServerError =              1011,
    NSURLSessionWebSocketCloseCodeTLSHandshakeFailure =              1015,
} API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0));

/** 使用指定的 closeCode 發(fā)送一個關閉幀礼患,同時可以提供關閉的原因
 * @param closeCode 關閉連接的原因
 * @param reason 進一步解釋為何關閉,由客戶端自定義掠归,可傳 nil缅叠;
 * @note 如果調用 [NSURLSessionTask cancel] 而非該方法,它會發(fā)送一個沒有closeCode或reason的關閉幀虏冻;
*/
- (void)cancelWithCloseCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData * _Nullable)reason;

/** 連接關閉原因仇让,可以在任何時候查看
 * 當連接尚未關閉時呀闻,此值為 NSURLSessionWebSocketCloseCodeInvalid
 *
 *  <ul> NSURLSessionWebSocketCloseCode : 說明 WebSocket 連接關閉的原因
 *     <li> NSURLSessionWebSocketCloseCodeInvalid   表示連接仍處于打開狀態(tài)
 *     <li> NSURLSessionWebSocketCloseCodeNormalClosure 表示連接正常關閉
 *     <li> NSURLSessionWebSocketCloseCodeGoingAway 表示服務器宕機或瀏覽器從頁面導航離開卫键,導致端點即將消失
 *     <li> NSURLSessionWebSocketCloseCodeProtocolError 表示端點由于協議錯誤而終止連接
 *     <li> NSURLSessionWebSocketCloseCodeUnsupportedData 表示端點接收到不能處理的數據類型后終止連接:如只接收文本的端點接收到二進制消息
 *     <li> NSURLSessionWebSocketCloseCodeNoStatusReceived 表示端點需要狀態(tài)碼而沒有接收到狀態(tài)碼
 *     <li> NSURLSessionWebSocketCloseCodeAbnormalClosure  表示連接在沒有關閉幀的情況下關閉
 *     <li> NSURLSessionWebSocketCloseCodeInvalidFramePayloadData 表示服務器接收到與消息類型不一致的數據而終止連接
 *     <li> NSURLSessionWebSocketCloseCodePolicyViolation 表示端點終止連接熬粗,因為它收到了違反其策略的消息
 *     <li> NSURLSessionWebSocketCloseCodeMessageTooBig 表示端點因接收到無法處理的大消息而終止連接
 *     <li> NSURLSessionWebSocketCloseCodeMandatoryExtensionMissing 表示客戶端終止連接,因為服務器沒有協商所需的擴展蛮穿;
 *                                      RFC 6455指示客戶端應該提供一個包含所需擴展的列表
 *     <li> NSURLSessionWebSocketCloseCodeInternalServerError 表示服務器因意外情況而終止連接
 *     <li> NSURLSessionWebSocketCloseCodeTLSHandshakeFailure 表示由于未能執(zhí)行TLS握手而關閉連接
 *  </ul>
 */
@property (readonly) NSURLSessionWebSocketCloseCode closeCode;

/** 連接關閉的詳細原因庶骄,可以在任何時候查看
 * nil 表示沒有closeReason,也或許 SocketTask 仍在運行
 */
@property (nullable, readonly, copy) NSData *closeReason;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末践磅,一起剝皮案震驚了整個濱河市单刁,隨后出現的幾起案子,更是在濱河造成了極大的恐慌府适,老刑警劉巖幻碱,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異细溅,居然都是意外死亡褥傍,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門喇聊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恍风,“玉大人,你說我怎么就攤上這事誓篱∨蟊幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵窜骄,是天一觀的道長锦募。 經常有香客問我,道長邻遏,這世上最難降的妖魔是什么糠亩? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任虐骑,我火速辦了婚禮,結果婚禮上赎线,老公的妹妹穿的比我還像新娘廷没。我一直安慰自己,他們只是感情好垂寥,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布颠黎。 她就那樣靜靜地躺著,像睡著了一般滞项。 火紅的嫁衣襯著肌膚如雪狭归。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天文判,我揣著相機與錄音唉铜,去河邊找鬼。 笑死律杠,一個胖子當著我的面吹牛,可吹牛的內容都是我干的竞惋。 我是一名探鬼主播柜去,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拆宛!你這毒婦竟也來了嗓奢?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤浑厚,失蹤者是張志新(化名)和其女友劉穎股耽,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體钳幅,經...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡物蝙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了敢艰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诬乞。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钠导,靈堂內的尸體忽然破棺而出震嫉,到底是詐尸還是另有隱情,我是刑警寧澤牡属,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布票堵,位于F島的核電站,受9級特大地震影響逮栅,放射性物質發(fā)生泄漏悴势。R本人自食惡果不足惜窗宇,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞳浦。 院中可真熱鬧担映,春花似錦、人聲如沸叫潦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矗蕊。三九已至短蜕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間傻咖,已是汗流浹背朋魔。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卿操,地道東北人警检。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像害淤,于是被迫代替她去往敵國和親扇雕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354