NSURLSession的基礎(chǔ)用法

NSURLSession的基礎(chǔ)用法

    - (void)viewDidLoad {
    [super viewDidLoad];
   
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[[NSOperationQueue alloc] init]]; 
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kRemotePAJsonURL]];
    req.HTTPMethod = @"POST";
    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:req];
    [dataTask resume];
    NSLog(@"本次dataTask:%@", dataTask);
}
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    NSLog(@"收到響應(yīng):%@     \ndataTask:%@", response, dataTask);
    
    self.mData = [NSMutableData data];
    
    NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
    completionHandler(disposition);
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    NSLog(@"%@收到data:%ld",[NSThread currentThread] ,data.length);
    
    [self.mData appendData:data];
    
    if (self.mData.length > 3000) {
        [dataTask cancel];
    }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
    NSLog(@"完成, error:%@", error);
    if (!error) {
        //在完成的時(shí)候,之前收到的data怎么取到?不借助其他的變量,在該方法里取不到?
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.mData options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"%@", dict);
    }
    //不把本次session Invalidate,那么session持有的delegate不會(huì)被釋放.
    [session finishTasksAndInvalidate];
}

對(duì)于方法

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration 
                                  delegate:(nullable id <NSURLSessionDelegate>)delegate 
                             delegateQueue:(nullable NSOperationQueue *)queue;

delegate和delegateQueue會(huì)被urlSession強(qiáng)引用.按蘋果的文檔說(shuō)明:delegate會(huì)在URLSession:didBecomeInvalidWithError結(jié)束后釋放.但事實(shí)上,要想讓delegate在didBecomeInvalidWithError結(jié)束后釋放,需要先把session Invalidate.否則,session持有的delegate不會(huì)被釋放.這句話的正確理解應(yīng)該是,當(dāng)一個(gè)session invalidate后,delegate要等到URLSession:didBecomeInvalidWithError結(jié)束后才會(huì)被釋放.對(duì)于delegateQueue,實(shí)際使用時(shí)delegateQueue不能是主隊(duì)列的.當(dāng)delegateQueue不是主隊(duì)列時(shí),didReceiveData:方法將隨機(jī)在某個(gè)線程執(zhí)行.

基本上一個(gè)APP,生成一個(gè)urlSession就夠了.沒(méi)必要一次請(qǐng)求,創(chuàng)建一個(gè)session,請(qǐng)求結(jié)束后又將session Invalidate.因此也就沒(méi)必要去管delegate和delegateQueue的內(nèi)存釋放問(wèn)題,這三個(gè)對(duì)象基本上是等到APP結(jié)束才會(huì)銷毀的.最佳做法之一就是使用GCD確保只生成一個(gè)session,然后使用該session來(lái)管理所有的請(qǐng)求.

對(duì)于代理方法: - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
在該方法中,為什么收到響應(yīng)后,還要調(diào)用completionHandler block?
因?yàn)樵谠摲椒ㄖ?通過(guò)disposition參數(shù),調(diào)用completionHandler后,可以更細(xì)粒度的控制本次請(qǐng)求是繼續(xù)還是取消還是轉(zhuǎn)為下載任務(wù).如果是取消,則后面請(qǐng)求的響應(yīng)體不會(huì)接收.如果是轉(zhuǎn)為下載任務(wù),那么通過(guò)調(diào)用completionHandler,NSURLSession將調(diào)用Delegate的 URLSession:dataTask:didBecomeDownloadTask:方法并將新生成的Download task對(duì)象作為參數(shù)傳入。在此調(diào)用之后,Delegate將不再接收來(lái)自Data task的回調(diào)消息,并開始接收Download task的回調(diào)消息。
注意:如果不調(diào)用

NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
completionHandler(disposition);

后面的didReceiveData:代理方法將不會(huì)執(zhí)行.

疑問(wèn)

  1. NSURLSession對(duì)象是被誰(shuí)強(qiáng)引用了?如何釋放?
    NSURLSession對(duì)象應(yīng)該是被系統(tǒng)的runloop強(qiáng)引用了,就類似于定時(shí)器一樣,需要invalid后,才會(huì)被釋放銷毀.
    題外話:如果timer屬性是strong,那么invalidate后最好將其置為nil,否則invalid后timer因?yàn)檫€有人持有它,而不能銷毀.strong情況下,timer的釋放: [self.timer invalidate];self.timer = nil;定時(shí)器對(duì)象是注冊(cè)到runloop里的,應(yīng)該通過(guò)invalidate來(lái)告訴runloop釋放它.所以self不應(yīng)該持有該對(duì)象,因此timer屬性最好為weak.

  2. NSURLSession的生命周期?

  3. 在didCompleteWithError:完成的時(shí)候,之前收到的data怎么取到?不借助其他的變量,在該方法里取不到?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容