開發(fā)只懂 AFN 盈魁?搞定 NSURLSession 才是硬道理

由于蘋果在 iOS9 之后已經(jīng)放棄了 NSURLConnection捕儒,所以在現(xiàn)在的實際開發(fā)中,除了大家常見的 AFN 框架,一般使用的是 NSURLSession。

目錄

  1. NSURLSession 的優(yōu)勢
  2. NSURLSessionTask 的子類
  3. NSURLSessionDataTask 發(fā)送 GET 請求
  4. NSURLSessionDataTask 發(fā)送 POST 請求
  5. NSURLSessionDataTask 設(shè)置代理發(fā)送請求
  6. 設(shè)置代理之后的強引用問題
  7. NSURLSessionDataTask 簡單下載
  8. NSURLSessionDownloadTask 簡單下載
  9. dataTask 和 downloadTask 下載對比
  10. 寫在最后
  11. 【補充】NSURLSession 詳解離線斷點下載的實現(xiàn)

NSURLSession 的優(yōu)勢

  • NSURLSession 支持 http2.0 協(xié)議
  • 在處理下載任務(wù)的時候可以直接把數(shù)據(jù)下載到磁盤
  • 支持后臺下載|上傳
  • 同一個 session 發(fā)送多個請求,只需要建立一次連接(復用了TCP)
  • 提供了全局的 session 并且可以統(tǒng)一配置评疗,使用更加方便
  • 下載的時候是多線程異步處理,效率更高

NSURLSessionTask 的子類

  • NSURLSessionTask 是一個抽象類茵烈,如果要使用那么只能使用它的子類
  • NSURLSessionTask 有兩個子類
    • NSURLSessionDataTask,可以用來處理一般的網(wǎng)絡(luò)請求百匆,如 GET | POST 請求等
      • NSURLSessionDataTask 有一個子類為 NSURLSessionUploadTask,用于處理上傳請求的時候有優(yōu)勢
    • NSURLSessionDownloadTask,主要用于處理下載請求,有很大的優(yōu)勢
NSURLSession 的子類

NSURLSessionDataTask 發(fā)送 GET 請求

發(fā)送 GET 請求的步驟非常簡單呜投,只需要兩步就可以完成:

  1. 使用 NSURLSession 對象創(chuàng)建 Task
  2. 執(zhí)行 Task
//確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520&type=JSON"];
    //創(chuàng)建 NSURLSession 對象
    NSURLSession *session = [NSURLSession sharedSession];
    
    /**
     根據(jù)對象創(chuàng)建 Task 請求
     
     url  方法內(nèi)部會自動將 URL 包裝成一個請求對象(默認是 GET 請求)
     completionHandler  完成之后的回調(diào)(成功或失敿有佟)
     
     param data     返回的數(shù)據(jù)(響應(yīng)體)
     param response 響應(yīng)頭
     param error    錯誤信息
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:
                ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //解析服務(wù)器返回的數(shù)據(jù)
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        //默認在子線程中解析數(shù)據(jù)
        NSLog(@"%@", [NSThread currentThread]);
    }];
    //發(fā)送請求(執(zhí)行Task)
    [dataTask resume];

NSURLSessionDataTask 發(fā)送 POST 請求

發(fā)送 POST 請求的步驟與發(fā)送 GET 請求一樣:

  1. 使用 NSURLSession 對象創(chuàng)建 Task
  2. 執(zhí)行 Task
//確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    //創(chuàng)建可變請求對象
    NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
    //修改請求方法
    requestM.HTTPMethod = @"POST";
    //設(shè)置請求體
    requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    //創(chuàng)建會話對象
    NSURLSession *session = [NSURLSession sharedSession];
    //創(chuàng)建請求 Task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM completionHandler:
                ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //解析返回的數(shù)據(jù)
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    //發(fā)送請求
    [dataTask resume];

NSURLSessionDataTask 設(shè)置代理發(fā)送請求

  1. 創(chuàng)建 NSURLSession 對象設(shè)置代理
  2. 使用 NSURLSession 對象創(chuàng)建 Task
  3. 執(zhí)行 Task
//確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    //創(chuàng)建可變請求對象
    NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
    //設(shè)置請求方法
    requestM.HTTPMethod = @"POST";
    //設(shè)置請求體
    requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    //創(chuàng)建會話對象,設(shè)置代理
    /**
     第一個參數(shù):配置信息
     第二個參數(shù):設(shè)置代理
     第三個參數(shù):隊列仑荐,如果該參數(shù)傳遞nil 那么默認在子線程中執(zhí)行
     */
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                 delegate:self delegateQueue:nil];
    //創(chuàng)建請求 Task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM];
    //發(fā)送請求
    [dataTask resume];
  1. 遵守協(xié)議雕拼,實現(xiàn)代理方法(常用的有三種代理方法)
-(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask 
didReceiveResponse:(nonnull NSURLResponse *)response 
completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler {
        //子線程中執(zhí)行
        NSLog(@"接收到服務(wù)器響應(yīng)的時候調(diào)用 -- %@", [NSThread currentThread]);
    
        self.dataM = [NSMutableData data];
        //默認情況下不接收數(shù)據(jù)
        //必須告訴系統(tǒng)是否接收服務(wù)器返回的數(shù)據(jù)
        completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    
        NSLog(@"接受到服務(wù)器返回數(shù)據(jù)的時候調(diào)用,可能被調(diào)用多次");
        //拼接服務(wù)器返回的數(shù)據(jù)
        [self.dataM appendData:data];
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    
        NSLog(@"請求完成或者是失敗的時候調(diào)用");
        //解析服務(wù)器返回數(shù)據(jù)
        NSLog(@"%@", [[NSString alloc] initWithData:self.dataM encoding:NSUTF8StringEncoding]);
}

設(shè)置代理之后的強引用問題

  • NSURLSession 對象在使用的時候,如果設(shè)置了代理释漆,那么 session 會對代理對象保持一個強引用悲没,在合適的時候應(yīng)該主動進行釋放

  • 可以在控制器調(diào)用 viewDidDisappear 方法的時候來進行處理篮迎,可以通過調(diào)用 invalidateAndCancel 方法或者是 finishTasksAndInvalidate 方法來釋放對代理對象的強引用

    • invalidateAndCancel 方法直接取消請求然后釋放代理對象
    • finishTasksAndInvalidate 方法等請求完成之后釋放代理對象男图。
    [self.session finishTasksAndInvalidate];
    

NSURLSessionDataTask 簡單下載

在前面請求數(shù)據(jù)的時候就相當于一個簡單的下載過程示姿,NSURLSessionDataTask 下載文件具體的步驟與上類似:

  1. 使用 NSURLSession 對象創(chuàng)建一個 Task 請求
  2. 執(zhí)行請求
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:
        @"http://120.25.226.186:32812/resources/images/minion_01.png"] 
        completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //解析數(shù)據(jù)
        UIImage *image = [UIImage imageWithData:data];
        //回到主線程設(shè)置圖片
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
        });
        
    }] resume];

NSURLSessionDownloadTask 簡單下載

  1. 使用 NSURLSession 對象創(chuàng)建下載請求
  2. 在下載請求中移動文件到指定位置
  3. 執(zhí)行請求
//確定請求路徑
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
    //創(chuàng)建請求對象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //創(chuàng)建會話對象
    NSURLSession *session = [NSURLSession sharedSession];
    //創(chuàng)建會話請求
    //優(yōu)點:該方法內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫沙盒的操作,解決了內(nèi)存飆升的問題
    NSURLSessionDownloadTask *downTask = [session downloadTaskWithRequest:request 
        completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //默認存儲到臨時文件夾 tmp 中逊笆,需要剪切文件到 cache
        NSLog(@"%@", location);//目標位置
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]  
                            stringByAppendingPathComponent:response.suggestedFilename];
        
        /**
         fileURLWithPath:有協(xié)議頭
         URLWithString:無協(xié)議頭
         */
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
        
    }];
    //發(fā)送請求
    [downTask resume];

以上方法無法監(jiān)聽下載進度栈戳,如要獲取下載進度,可以使用代理的方式進行下載难裆。

dataTask 和 downloadTask 下載對比

  • NSURLSessionDataTask
    • 下載文件可以實現(xiàn)離線斷點下載子檀,但是代碼相對復雜
  • NSURLSessionDownloadTask
    • 下載文件可以實現(xiàn)斷點下載,但不能離線斷點下載
    • 內(nèi)部已經(jīng)完成了邊接收數(shù)據(jù)邊寫入沙盒的操作
    • 解決了下載大文件時的內(nèi)存飆升問題

寫在最后

關(guān)于使用 NSURLSession 進行上傳文件操作乃戈,我只想說真的很麻煩褂痰,建議大家時間充沛且有興趣的可以研究一下,如果不想研究也是可以的症虑,繼續(xù)使用我們偉大的 AFN 框架就好缩歪。至于 AFN 框架的使用,這里就不贅述了谍憔,后期如果有時間會更新一些常用的 AFN 使用方法匪蝙,敬請期待。

附:使用 NSURLSession 上傳文件主要步驟及注意點

  • 主要步驟:
    1. 確定上傳請求的路徑( NSURL )
    2. 創(chuàng)建可變的請求對象( NSMutableURLRequest )
    3. 修改請求方法為 POST
    4. 設(shè)置請求頭信息(告知服務(wù)器端這是一個文件上傳請求)
    5. 按照固定的格式拼接要上傳的文件等參數(shù)
    6. 根據(jù)請求對象創(chuàng)建會話對象( NSURLSession 對象)
    7. 根據(jù) session 對象來創(chuàng)建一個 uploadTask 上傳請求任務(wù)
    8. 執(zhí)行該上傳請求任務(wù)(調(diào)用 resume 方法)
    9. 得到服務(wù)器返回的數(shù)據(jù)习贫,解析數(shù)據(jù)(上傳成功 | 上傳失敼淝颉)
  • 注意點:
    1. 創(chuàng)建可變的請求對象,因為需要修改請求方法為 POST苫昌,設(shè)置請求頭信息

    2. 設(shè)置請求頭這個步驟可能會被遺漏

    3. 要處理上傳參數(shù)的時候颤绕,一定要按照固定的格式來進行拼接

    4. 需要采用合適的方法來獲得上傳文件的二進制數(shù)據(jù)類型( MIMEType,獲取方式如下)

      • 點擊這里搜索
      • 對著該文件發(fā)送一個網(wǎng)絡(luò)請求蜡歹,接收到該請求響應(yīng)的時候屋厘,可以通過響應(yīng)頭信息中的 MIMEType 屬性得到
      • 使用通用的二進制數(shù)據(jù)類型表示任意的二進制數(shù)據(jù) application/octet-stream
      • 調(diào)用 C 語言的 API 來獲取
      [self mimeTypeForFileAtPath:@"此處為上傳文件的路徑"]
      
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市月而,隨后出現(xiàn)的幾起案子汗洒,更是在濱河造成了極大的恐慌,老刑警劉巖父款,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溢谤,死亡現(xiàn)場離奇詭異,居然都是意外死亡憨攒,警方通過查閱死者的電腦和手機世杀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肝集,“玉大人瞻坝,你說我怎么就攤上這事⌒诱埃” “怎么了所刀?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵衙荐,是天一觀的道長。 經(jīng)常有香客問我浮创,道長忧吟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任斩披,我火速辦了婚禮溜族,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垦沉。我一直安慰自己煌抒,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布厕倍。 她就那樣靜靜地躺著摧玫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绑青。 梳的紋絲不亂的頭發(fā)上诬像,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音闸婴,去河邊找鬼坏挠。 笑死,一個胖子當著我的面吹牛邪乍,可吹牛的內(nèi)容都是我干的降狠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼庇楞,長吁一口氣:“原來是場噩夢啊……” “哼榜配!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吕晌,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蛋褥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后睛驳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烙心,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年乏沸,在試婚紗的時候發(fā)現(xiàn)自己被綠了淫茵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹬跃,死狀恐怖匙瘪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤丹喻,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布算灸,位于F島的核電站,受9級特大地震影響驻啤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荐吵,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一骑冗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧先煎,春花似錦贼涩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至占锯,卻和暖如春袒哥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背消略。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工堡称, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艺演。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓却紧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胎撤。 傳聞我的和親對象是個殘疾皇子晓殊,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容