天天看點

iOS 網絡請求 筆記一、url請求二、執行url請求

有關網絡請求的類(該圖檔來自:developer.apple.com)

iOS 網絡請求 筆記一、url請求二、執行url請求

一、url請求

網絡請求的組成部分有伺服器位址、請求參數,以及請求方式。在iOS中,一個網絡請求用NSURLRequest(或者其子類NSMutableURLRequest)來表示。

NSURLRequest适合于get請求,NSMutableURLRequest可以是post請求。

get方式下,伺服器位址和請求參數都可以明文包含在url中,可以直接使用這個url來建立NSURLRequest(或者NSMutableURLRequest)。

post方式下,伺服器位址用NSURL來表示,請求參數可以封裝到NSData中(也可以以檔案或者流的形式儲存)。由于需要将伺服器位址和請求參數分開,是以需要用到NSMutableURLRequest類。用伺服器位址的url建立NSMutableURLRequest對象,然後将封裝了請求參數的NSData對象添加到這個NSMutableURLRequest對象中。示例如下:

NSURL *url=[NSURL URLWithString:@“http://ipad-bjwb.bjd.com.cn/DigitalPublication/publish/Handler/APINewsList.ashx"];
NSData *data=[@"date=20151101&startRecord=1&len=5&udid=1234567890&terminalType=Iphone&cid=213" dataUsingEncoding:NSUTF8StringEncoding];           

然後将伺服器位址與請求參數加入到NSMutableURLRequest對象中:

NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:60];
request.HTTPMethod[email protected]"post";//指明請求方式為post,預設為get
request.HTTPBody=data;           

這樣就準備好了一個網絡請求,接下來就是如何去執行這個網絡請求的問題。

二、執行url請求

執行url請求可以使用iOS原生API也可以使用第三方庫。

執行url請求的兩個原生方法:

(1)NSURLSession

(2)NSURLConnection

iOS 7.0 以後推薦使用NSURLSession,以前使用NSURLConnection。

NSURLSession、NSURLConnection都可以發送和接收以NSData或者檔案的形式儲存的資料.

實作url請求的第三方庫有afNetworking、sdWebImage等。

1.兩個原生方法的基本使用思路

(1)每個項目都有一個NSURLSession對象,可以通過[NSURLSession sharedSession]方法來擷取它,然後就可以用它來建立請求任務。該任務調用resume方法後開始執行。請求任務有三種,上傳、下載下傳、資料。通過NSURLSession來執行url請求是異步的。

(2)NSURLConnection直接執行send方法(類方法)發送請求,可以選擇同步也可以選擇異步。異步發送請求接收資料的話可以使用block接收,也可以使用代理。注意如果使用代理來接收資料,資料會是斷續接收的。通常使用block比較友善。

同步和異步的差別就是,同步就是執行完網絡請求方法後,要等到網絡請求得到響應并完成資料傳輸之後才傳回,異步就是發送完請求之後馬上傳回。

2. NSURLSession詳解

擷取session可以通過初始化方法,也可以直接使用項目預設的session對象,通過sharedSession方法擷取。初始化session對象需要指定代理,如果指定為nil,就是使用系統預設的代理。

(1)session的分類

session分為3種:

  • 預設的(default session):會将存儲資料存到硬碟上。
  • 短暫的(ephemeral session):不會存儲任何資料到硬碟上,隻會占用記憶體,當session釋放了,所有的資料也就沒有了。
  • 背景的(background session):和預設的session的差別在于會用獨立的過程來處理資料傳輸。

初始化session的時候需要指定一個NSURLSessionConfiguration對象,session的類型就由這個對象的類型來确定。

(2)任務task的分類

任務分為3種,資料、下載下傳、上傳:

  • data task資料任務:發送和接收NSData形式的資料
  • download task下載下傳任務:解析檔案形式的資料,支援app沒有運作的時候在背景執行。
  • upload task上傳任務:發送檔案形式的資料,也支援背景執行。

(3)任務task和session的關系

  • 任務的初始化和任務的管理都由session來完成。
  • 每個session對象管理着它自己建立的任務。
  • 任務建立後需要執行resume方法,session才會處理它。
  • 任務處理的具體操作是由session的代理來完成的,也就是說具體的處理會寫在代理方法中。

(4)利用session完成背景傳輸

需要注意的問題:

  • 隻有背景類型的session才可以建立支援背景傳輸的任務(下載下傳任務或上傳任務)。而且背景上傳隻支援檔案上傳,如果上傳的是NSData對象或者資料流,在app退出後就會斷掉。
  • 背景任務隻支援http和https協定,不支援自定義協定。
  • 如果背景傳輸的任務是在app已經進入了背景之後才初始化的,那麼session的NSURLSessionConfiguration對象的discretionary屬性值為true。
  • 由于網絡錯誤導緻的背景上傳或背景下載下傳任務失敗,系統會自動重新嘗試執行這些任務,是以不需要自己寫代碼來重新執行失敗的背景任務。

背景任務與app的互動:

背景任務的特點就是運作在背景,當app不在運作的時候背景任務仍然可以運作。

上面說過,任務的處理是由session的代理方法來完成的,但是當app沒有運作的時候,session已經被釋放,這時候背景任務怎麼和建立這個任務的session重新關聯起來呢?

這個問題iOS系統已經有一套完整的機制去處理它。是這樣的:當背景任務完成或者需要認證的時候,如果app沒有在運作,系統就會喚醒app,并調用app delegate的

(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler

方法。這個方法就是特地寫來處理背景任務的,下面所描述的内容都圍繞這個方法來展開。

需要重寫在這個方法,在這個方法中讓背景任務和session重新關聯起來。由于建立它的session已經釋放,要找回它不可能,實際的做法是建立一個和它一樣的session,然後讓任務與這個session關聯起來。具體就是用這個方法的參數identifier來建立一個NSURLSessionConfiguration對象,并且用這個NSURLSessionConfiguration對象建立一個session,這個session就可以當成是原來的session了。神奇的是,隻要這樣建立了session,正在運作的任務就會自動和它關聯起來,至于是怎麼做到了,不需要操心,系統已經解決了。

留意到這個方法有一個block類型的參數completionHandler,它的意義在于,一旦它被執行就表明背景任務處理完成,是以系統自喚醒app之後就會一直等待completionHandler的執行,以便讓app重新停止運作。是以,要記得把completionHandler傳給session的代理,并且在session的代理方法URLSessionDidFinishEventsForBackgroundURLSession:中調用它,這樣就實作了在最後一個任務處理完畢以後讓app再次進入背景。

在正在運作的任務已經和session重新取得聯系之後就會調用其代理的相關方法,如果是背景任務完成,就會調用URLSession:downloadTask:didFinishDownloadingToURL:方法。如果是需要認證,就會調用URLSession:task:didReceiveChallenge:completionHandler:方法或者URLSession:didReceiveChallenge:completionHandler:方法。

官網例子:https://developer.apple.com/library/ios/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013416

(4)下載下傳檔案

與檔案下載下傳有關的協定方法:

  • URLSession:downloadTask:didFinishDownloadingToURL:

    檔案下載下傳完成後調用,可以擷取下載下傳好的檔案的url
  • URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:

    下載下傳過程中調用
  • URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:

    該方法在開始恢複一個失敗的下載下傳任務之後調用
  • URLSession:task:didCompleteWithError:

    下載下傳任務完成或終止後調用,如果任務出錯,可以擷取到NSError對象
  • 終止下載下傳任務

    可以調用

    NSURLSessionDownloadTask

    對象的方法:

    cancelByProducingResumeData:

  • 恢複下載下傳任務

    可以調用

    session

    downloadTaskWithResumeData:

    downloadTaskWithResumeData:completionHandler:

    這裡的resumeData從協定方法

    URLSession:task:didCompleteWithError:

    中的NSError對象的userInfo字典中會有,對應key為

    NSURLSessionDownloadTaskResumeData

(5)重定向

相關協定方法:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler           

對于預設的session和暫時的session管理的url請求任務發生重定向時就會調用這個方法,而背景任務發生重定向會直接服從重定向。

在這個方法裡面,可以擷取到新的url請求,調用

completionHandler(request);

就會允許重定向。如果調用

completionHandler(nil);

就相當于拒絕重定向。當然也可以調用

completionHandler(otherRequest);

實作自定義重定向。