【轉載】NSURLSession教程

 

原文:http://www.raywenderlich.com/51127/nsurlsession-tutorial

 

 

查理·富爾頓

NSURLSession Tutorial

注意從雷 :這是一個縮寫版的一章 iOS 7教程 咱們發佈的一部分 iOS 7盛宴 。 咱們但願你能喜歡! git

每個新的iOS版本包含了一些很棒的新的網絡api,和iOS 7也不例外。 在iOS 7中,蘋果推出了 NSURLSession ,這是一套類取代 NSURLConnection 做爲網絡的首選方法。 github

在這NSURLSession教程中,您將學習這個新類是什麼,爲何和應該如何使用它,如何比較以前的,最重要的是:獲得實踐整合成一個真正的應用程序! web

請注意,本教程假設您熟悉基本的網絡概念。 若是你是全新的網絡,你仍然能夠跟隨一切都是一步一步的,但可能會有一些不熟悉的概念,你可能須要查找。 json

爲何使用NSURLSession ?

你爲何要使用 NSURLSession 嗎? 它帶給你一些新優點和好處: api

  • 後臺上傳和下載: 只有當一個配置選項 NSURLSession 建立,獲得全部背景網絡的好處。 這有助於與電池壽命,支持UIKit多任務和使用相同的委託模型做爲進程內轉移。
  • 暫停和恢復網絡操做能力: 稍後您將看到,NSURLSession API的任何網絡任務能夠暫停,中止,並從新啓動。 沒有必要NSOperation生成子類。
  • 可配置的容器: 每個 NSURLSession 是可配置爲將請求放入容器。 例如,若是您須要設置一個HTTP頭的選擇你只須要這樣作一次,每一個請求的會話將會有相同的配置。
  • Subclassable和私人存儲: NSURLSession subclassable,您能夠配置一個會話使用的私有存儲在每一個會話的基礎上。 這容許您有私人存儲對象以外的全局狀態。
  • 改進的認證處理: 身份驗證是在特定的鏈接的基礎上完成的。 當使用 NSURLConnection 若是身份驗證發出挑戰,挑戰爲任意請求會回來,你不會知道請求的挑戰。 與 NSURLSession ,委託處理身份驗證。 數組

  • 豐富的委託模型: NSURLConnection 有一些基於異步阻塞方法,可是不能使用一個委託。 當請求使其做品或失敗,即便須要身份驗證。 與 NSURLSession 你能夠有一個混合的方法,使用基於異步阻塞方法並設置一個委託處理身份驗證。
  • 上傳和下載的文件系統: 這鼓勵分離數據(文件內容)的元數據(URL和設置)。

NSURLSession vs NSURLConnection

「哇,NSURLSession聽起來複雜! 」,你可能會想。 「也許我會堅持個人老朋友NSURLConnection。」 瀏覽器

別擔憂——使用 NSURLSession 使用其predecessory同樣簡單 NSURLConnection 對於簡單的任務。 爲一個例子,讓咱們看看一個例子的一個簡單的網絡調用JSON的最新天氣在倫敦。 緩存

假設您有這NSString構造NSURL: 安全

NSString *londonWeatherUrl = @"http://api.openweathermap.org/data/2.5/weather?q=London,uk";

首先是如何使這個調用時使用 NSURLConnection : 服務器

NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:londonWeatherUrl]];   [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // handle response }];

如今,讓咱們使用 NSURLSession 。 注意,這是最簡單的方法快速使用 NSURLSession 。 後來在本教程中,您將看到如何配置會話和設置其餘功能,如表明團。

NSURLSession *session = [NSURLSession sharedSession]; [[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // handle response   }] resume];

請注意,您不須要指定運行隊列。 除非特別指定,不然將調用後臺線程。 它可能很難注意到這兩個之間的差別,這是由設計。 蘋果提到dataTaskWithURL旨在取代sendAsynchronousRequest NSURLConnection

因此基本上, NSURLSession 同樣容易使用嗎 NSURLConnection 對於簡單的任務,有一組豐富的額外的功能,當你須要它。

NSURLSession vs AFNetworking

討論網絡代碼沒有徹底不提到AFNetworking框架。 這是一個最流行的框架用於iOS / OS X,創造的輝煌Mattt湯普森。

注意: 瞭解更多關於AFNetworking,結賬github頁面發現: https://github.com/AFNetworking/AFNetworking 。 咱們也有一個教程:
http://www.raywenderlich.com/30445/afnetworking-crash-course

這就是相同的數據任務的代碼看起來像使用AFNetworking 1. x:

NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:londonWeatherUrl]];   AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { // handle response } failure:nil]; [operation start];

使用AFNetworking的好處之一是數據類型的類來處理響應數據。 使用AFJSONRequestOperation(或相似的類XML plist)塊已經成功爲您解析響應並返回的數據。 與 NSURLSession 你收到NSData完成處理器,因此你須要把NSData轉換成JSON或其餘格式。

注意: 您能夠輕鬆地將NSData轉換成JSON使用NSJSONSerialization類中引入iOS 5。 爲了瞭解更多,看看23章 iOS 5的教程 「使用JSON」。

因此您可能想知道若是你應該使用AFNetworking仍是堅持 NSURLSession

就我我的而言,我認爲最好是堅持簡單的需求 NSURLSession ——這能夠避免沒必要要的第三方依賴引入您的項目。 新表明,配置和基於任務的API的不少「缺失的功能」AFNetworking添加如今包括在內。

然而,若是你想使用2.0的一些新特性中發現AFNetworking序列化和進一步UIKit集成(除了UIImageView類別),那麼很難反對使用它!

注意: 的2.0分支AFNetworking,轉換到使用 NSURLSession 。 有關更多信息,請參見這篇文章:
https://github.com/afnetworking/afnetworking/wiki/afnetworking - 2.0 -遷移-指南

引入字節俱樂部

在這NSURLSession教程中,您將探索這種新的API經過構建一個筆記和圖片共享應用程序之上Dropbox核心API的絕密組織命名爲字節俱樂部。

因此考慮本教程你正式邀請字節俱樂部! 字節俱樂部的第一條規矩,你可能會問? 沒有人談論字節俱樂部——除了那些很酷的足以閱讀本教程。 絕對不是那些Android用戶;他們終身禁止。 :]

頭在下一節開始構建應用程序,將做爲你的起始字節俱樂部。

請注意,本教程假設您擁有一些基本的熟悉網絡若是iOS在之前的版本中。 頗有幫助若是你使用api NSURLConnection NSURLSession 在過去。 若是你全新的網絡在iOS,您應該檢查咱們的iOS學徒系列初級開發者,而後再繼續學習本教程。

開始

字節俱樂部是獨家的iOS開發者加入分組進行編碼的挑戰。 由於每一個成員這些挑戰來自世界各地的遠程工做,成員也發現它有趣分享全景照片的「戰鬥」。

這裏有一個全景的照片光線的辦公室設置,例如:

ray's office

注意: 您可能想要建立本身的全景的照片,你的辦公室,頗有趣,而且它將在本教程中,晚些時候派上用場。

在iOS 7中,你能夠經過打開全景照片 照片 並選擇標籤命名 帕諾人

若是你喜歡結果,你能夠把它做爲你的鎖定屏幕的壁紙 設置 並選擇 亮度和壁紙\選擇壁紙\個人全景照片

固然字節俱樂部有本身的應用程序讓這一切發生。 您可使用應用程序建立編碼挑戰或與其餘成員分享全景照片。 在幕後,這是經過網絡實現,具體地說,經過共享文件Dropbox API。

Starter項目概述

首先,下載 本教程啓動項目。

這對你啓動項目包括UI預製,這樣你就能夠專一於本教程中的網絡應用程序的一部分。 starter項目還包括一些代碼來處理Dropbox認證,之後你會了解更多。

打開Xcode項目和你的設備或模擬器上運行它。 您應該看到一個屏幕是這樣的:

starter app login

然而,您將沒法登陸,您必須配置應用程序首先,你要作的。

主要的下一個開放。 故事板,看看這個應用程序的整體設計:

storyboard

這是一個基本選項卡應用與兩個選項卡:一個用於代碼的挑戰,一個全景照片。 還有一個步驟以前,記錄用戶的應用程序。你設置登陸在您建立Dropbox平臺下面的應用程序。

隨時查看應用程序的其他部分和熟悉有什麼到目前爲止。 你會發現除了受權組件,沒有網絡代碼檢索代碼挑戰或全景照片,那是你的工做!

建立一個新的Dropbox平臺應用

開始與你的Dropbox應用程序,打開Dropbox位於應用程序控制臺 https://www.dropbox.com/developers/apps

登陸若是您有一個Dropbox賬戶,但若是不是,沒有汗水:建立一個免費的Dropbox賬戶。 若是這是你第一次使用Dropbox API,你須要贊成Dropbox條款和條件。

在法律的東西,選擇建立應用程序選項。 你會面對一系列的問題——提供如下回復

  • 你想要什麼類型的應用程序建立?
    • 選擇: Dropbox API的應用程序
  • 你的應用程序須要什麼類型的數據存儲在Dropbox ?
    • 選擇: 文件和數據存儲
  • 你的應用能夠侷限於本身的,私人文件夾嗎?
    • 選擇: 不——個人程序須要訪問文件已經在Dropbox
  • 什麼類型的文件你的應用程序須要訪問嗎?
    • 選擇: 全部的文件類型

最後,爲應用程序提供一個名稱,無論你選擇什麼,只要它是獨一無二的。 Dropbox將讓你知道若是你選擇了一個名字,已經在使用。 您看到的屏幕應該相似以下:

dropbox app name

點擊 建立應用程序 和你的路上!

在下一個屏幕上,您將看到顯示屏幕包含 應用的關鍵 應用程序的祕密:

app key and secret

不要關閉這個屏幕;你須要應用程序下一步的關鍵和應用的祕密。

打開Dropbox 00 找到如下行:

#warning INSERT YOUR OWN API KEY and SECRET HERE
static NSString *apiKey = @"YOUR_KEY"; static NSString *appSecret = @"YOUR_SECRET";

填寫你的應用關鍵和祕密,和刪除#警惕線。 您能夠關閉Dropbox Web應用程序頁面。

接下來,建立一個文件夾的根目錄主要Dropbox文件夾並命名爲你的願望。 若是你與其餘Dropbox用戶和共享此文件夾發送字節俱樂部的構建應用程序,他們將可以建立筆記和上傳照片。

在Dropbox.m找到如下行:

#warning THIS FOLDER MUST BE CREATED AT THE TOP LEVEL OF YOUR DROPBOX FOLDER, you can then share this folder with others
NSString * const appFolder = @"byteclub";

將字符串值更改成Dropbox文件夾的名稱建立和刪除#警告編譯指示。

這個程序分發給其餘用戶,給他們訪問令牌,您須要打開「啓用額外用戶」設置爲你的Dropbox平臺應用。

Dropbox app控制檯 https://www.dropbox.com/developers/apps 。 點擊應用程序名,而後單擊啓用額外的用戶按鈕。 會出現一個對話框說你增長了用戶限制。 單擊對話框上的好清楚。 應用程序頁面將如今看起來像下面的:

user limit

注意: 您可能會注意到,當你開發你的應用,你能夠給100用戶訪問。 當你準備釋放真正的應用程序,你必須申請生產狀態,你能夠經過單擊 申請生產 Dropbox按鈕和發送一些額外的信息。

Dropbox將回顧你的應用程序,以確保它符合他們的指南,若是一切順利的話,他們將打開你的應用程序的API訪問無限的用戶。

Dropbox認證:概述

在您的應用程序可使用Dropbox API以前,你須要對用戶進行身份驗證。 在Dropbox,這是經過OAuth——一個流行的開源協議,容許安全受權。

本教程的重點是在網絡上,不是OAuth,因此我已經建立了一個小API Dropbox。 m處理大部分的給你。

若是您曾經使用過第三方twitter客戶端應用程序,像TweetBot,那麼你就會熟悉OAuth安裝過程當中從用戶的視角。 OAuth過程幾乎相同的應用程序。

構建和運行您的應用程序,並遵循的步驟登陸。 你會看到一個空白的屏幕上有兩個標籤,一個用於筆記和一個用於PanoPhotos,以下所示:

App Login

OAuth身份驗證發生在三個高水平的步驟:

  1. 得到一個OAuth請求令牌用於身份驗證過程的其他部分。 這是請求令牌。
  2. 一個網頁呈現給用戶經過web瀏覽器。 沒有用戶的受權在此步驟中,爲您的應用程序是不可能得到一個訪問令牌從步驟3。
  3. 第二步完成後,應用程序調用一個web服務交換臨時請求令牌(從步驟1)永久訪問令牌,這是存儲在應用程序中。

注意: 本教程保持簡潔,咱們不打算詳細Dropbox身份驗證是如何工做的。 然而,若是你想了解更多查看本教程的完整版的一部分 iOS 7教程

NSURLSession套類

蘋果公司描述 NSURLSession 做爲一個新類和套類。 有新工具上傳、下載、處理受權和處理HTTP協議的任何東西。

在開始編碼以前,重要的是要有一個好的理解的主要類 NSURLSession 套件以及它們如何一塊兒工做。

NSURLSession overview

一個 NSURLSession 是使用一個 NSURLSessionConfiguration 和一個可選的委託。 在您建立會話而後知足你網絡須要經過建立 NSURLSessionTask的

NSURLSessionConfiguration

有三種方法來建立一個 NSURLSessionConfiguration :

  • defaultSessionConfiguration ——建立一個配置對象,採用全局緩存,餅乾和證書存儲對象。 這是一個配置致使你的會話是最像 NSURLConnection
  • ephemeralSessionConfiguration ——這個配置是「私人」會話和沒有持久性存儲緩存,餅乾,或憑證存儲對象。
  • backgroundSessionConfiguration ——這是在當你想要使用的配置使網絡電話遠程推送通知或在應用程序暫停。 指17和18章 iOS 7教程 「初級和中級多任務」,爲更多的細節。

一旦你建立一個 NSURLSessionConfiguration 這樣,你能夠設置各類屬性:

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];   // 1 sessionConfig.allowsCellularAccess = NO;   // 2 [sessionConfig setHTTPAdditionalHeaders: @{@"Accept": @"application/json"}];   // 3 sessionConfig.timeoutIntervalForRequest = 30.0; sessionConfig.timeoutIntervalForResource = 60.0; sessionConfig.HTTPMaximumConnectionsPerHost = 1;
  1. 在這裏你只限制對wifi網絡操做。
  2. 這將設置全部請求只接受JSON響應。
  3. 這些屬性將配置資源或請求超時。 還能夠限制應用程序只有一個網絡鏈接到主機。

這些只是您能夠配置的一些事情,必定要檢查出一個完整的文檔列表。

NSURLSession

NSURLSession 設計做爲一個替代API NSURLConnection 。 經過他們的爪牙會話作全部的工做,也被稱爲 NSURLSessionTask 對象。 與 NSURLSession 您能夠建立任務使用基於塊的便利方法,設置一個委託,或二者兼而有之。 例如,若是你想下載一個圖像(* *)挑戰,你將須要建立一個 NSURLSessionDownloadTask

首先,您須要建立一個會話。 這裏有一個例子:

// 1
NSString *imageUrl = @"http://www.raywenderlich.com/images/store/iOS7_PDFonly_280@2x_authorTBA.png";   // 2 NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];   // 3 NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

好這只是有點不一樣於你所擁有的。 讓咱們去一步一步。

  1. 這個片斷咱們下載相同的兩個任務。
  2. 你老是首先建立一個NSURLConfiguration。
  3. 這將建立一個會話使用當前類做爲一個委託。

在您建立會話,您能夠下載圖像經過建立一個任務完成處理器,是這樣的:

// 1
NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:[NSURL URLWithString:imageUrl]   completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // 2 UIImage *downloadedImage = [UIImage imageWithData: [NSData dataWithContentsOfURL:location]]; //3 dispatch_async(dispatch_get_main_queue(), ^{ // do stuff with image _imageWithBlock.image = downloadedImage; }); }];   // 4 [getImageTask resume];

啊哈! 如今這看起來像一些網絡代碼!

  1. 任務老是由會話。 這是建立基於塊的方法。 記住你仍然可使用 NSURLSessionDownloadDelegate 跟蹤下載進度。 因此你獲得一箭雙鵰! (挑戰* *提示)
    -URLSession:downloadTask :didWriteData:totalBytesWritten :totalBytesExpectedToWrite:
  2. 你完成處理器提供的使用位置變量指針圖像。
  3. 例如,最後你能夠更新UIImageView顯示新文件的形象。 (提示提示 ☺)
  4. 你老是要啓動任務!
  5. 還記得我以前說過,一個會話能夠建立任務,將發送消息委託方法完成通知你,等。

這是看起來如何,使用相同的會話從上面:

// 1
NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:[NSURL URLWithString:imageUrl]];   [getImageTask resume];
  1. 這確定是更少的代碼 ☺然而,若是你只有這樣作時,你永遠不會看到任何東西。

你須要委託實現的一些方法 NSURLSessionDownloadDelegate 協議。

首先,咱們須要下載完成時獲得通知:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { // use code above from completion handler }

你再次提供文件下載到的位置,你能夠用它來處理圖像。

最後,若是你須要下載進度跟蹤,爲任務建立方法,您將須要使用如下:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { NSLog(@"%f / %f", (double)totalBytesWritten, (double)totalBytesExpectedToWrite); }

正如您能夠看到的, NSURLSessionTask 是真正的主力經過網絡完成的東西」。

NSURLSessionTask

到目前爲止,您已經看到 NSURLSessionDataTask NSURLSessionDownloadTask 在使用。 來自這兩個任務 NSURLSessionTask 這兩個基類,在這裏你能夠看到:

NSURLSessionTask classes

NSURLSessionTask 是在您的會話的基類任務,他們只能從一個會話,並建立一個子類。

NSURLSessionDataTask

這個任務發出HTTP GET請求從服務器下拉數據。 NSData形式返回的數據。 而後將這些數據轉換成正確的XML類型,JSON,界面圖像,plist等等。

NSURLSessionDataTask *jsonData = [session dataTaskWithURL:yourNSURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // handle NSData }];

NSURLSessionUploadTask

使用這個類當您須要上傳一些web服務使用HTTP POST或PUT命令。 委託任務時還容許您看好網絡流量的傳輸。

上傳一個圖像:

NSData *imageData = UIImageJPEGRepresentation(image, 0.6);   NSURLSessionUploadTask *uploadTask = [upLoadSession uploadTaskWithRequest:request fromData:imageData];

這裏的任務是建立一個會話和NSData圖片上傳。 還有上傳使用文件或流的方法。

NSURLSessionDownloadTask

NSURLSessionDownloadTask 能做到下載文件從遠程服務,暫停和恢復下載。 這個比其餘兩個子類有點不一樣。

  • 這種類型的任務將直接寫入一個臨時文件。
  • 下載會議期間將調用URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:更新狀態信息
  • 當任務完成後,URLSession:downloadTask:didFinishDownloadingToURL:。 這是當你能夠保存文件的一個永久的一個臨時位置。
  • 當下載失敗或取消了你能夠獲得數據恢復下載。

這個特性很是有用當俱樂部一個字節位置全景照片下載到你的設備的攝像頭。 你看到一個例子下載任務在上面的代碼片斷下載一個圖像。

上面全部的

上述全部任務建立掛起狀態;在建立一個您須要調用它的恢復方法以下證實:

[uploadTask resume];

taskIdentifier屬性容許您將唯一地標識一個任務在一個會話當你管理多個任務。
就是這樣! 如今你知道的主要類 NSURLSession 套房,讓咱們試試。

與NSURLSession分享筆記

好吧,這不是《死亡詩社》這是字節俱樂部! 是時候開始看看這個網絡代碼的行動。

您須要一種方法來發送消息到其餘字節俱樂部的成員。 既然你已經創建了一個訪問令牌,下一個步驟是先實例化NSURLSesssion並讓你調用Dropbox API。

建立一個NSURLSession

添加如下屬性 NotesViewController.m 剛剛NSArray *筆記:

@property (nonatomic, strong) NSURLSession *session;

您將建立全部的僕從上面從會話。

添加如下方法 NotesViewController.m 略高於initWithStyle:

- (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // 1 NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];   // 2 [config setHTTPAdditionalHeaders:@{@"Authorization": [Dropbox apiAuthorizationHeader]}];   // 3 _session = [NSURLSession sessionWithConfiguration:config]; } return self; }

這裏有一個comment-by-comment解釋上面的代碼:

  1. 應用程序調用initWithCoder當實例化一個視圖控制器從故事板,所以這是個完美的地方初始化和建立 NSURLSession 。 你不想要激進的緩存或持久性,因此你使用ephemeralSessionConfiguration便利方法,它返回一個會話緩存沒有持久性存儲,餅乾,或憑據。 這是一個「隱私瀏覽」配置。
  2. 接 下來,您將受權HTTP頭添加到配置對象。 的apiAuthorizationHeader我寫的是一個助手方法,它返回一個字符串,在OAuth規範格式。 這個字符串包含訪問令牌,令牌機密和Dropbox應用API鍵。 記住,這是必要的,由於每一個API調用Dropbox須要身份驗證。
  3. 最後,您將建立 NSURLSession 使用上面的配置。

這個會議如今準備建立的任何網絡任務,你須要在你的應用程序。

指出經過Dropbox API

模擬報告被另外一個用戶添加,添加任何你選擇的文本文件的文件夾設置根Dropbox文件夾。 下面的例子顯示了文件 用法 坐在 byteclub Dropbox文件夾:

example file

等到Dropbox確認同步文件,而後繼續下面的代碼。

將下面的代碼添加到空的 notesOnDropBox 方法 NotesViewController.m:

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES; // 1 NSURL *url = [Dropbox appRootURL];   // 2 NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { // TODO 1: More coming here! } }];   // 3 [dataTask resume];

這種方法的目的是獲取列表的文件在應用程序的Dropbox文件夾。 咱們這是如何工做的一段一段的。

  1. 在Dropbox,你能夠看到一個文件夾的內容經過一個通過驗證的GET請求特定的URL,好比https://api.dropbox.com/1/metadata/dropbox/byteclub。 我建立了一個方便的方法在Dropbox類爲您生成這個URL。
  2. NSURLSession 有方便的方法來輕鬆地建立各類類型的任務。 給你建立一個數據任務爲了執行GET請求URL。 當請求完成後,你的completionHandler塊。 你會添加一些代碼在一個時刻。
  3. 記得一個任務默認爲暫停狀態,因此你須要調用恢復方法開始運行。

這是全部您須要作的開始一個GET請求,如今讓咱們添加代碼來解析結果。 後添加如下行「TODO 1」評論:

// 1
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 200) {   NSError *jsonError;   // 2 NSDictionary *notesJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];   NSMutableArray *notesFound = [[NSMutableArray alloc] init];   if (!jsonError) { // TODO 2: More coming here! } }

這裏有兩個主要部分:

    1. 你知道你作了一個HTTP請求,響應將是一個HTTP響應。 這裏你把NSURLResponse NSHTTPURLRequest反應因此你能夠訪問statusCode財產。 若是你收到一個HTTP狀態碼200年一切都好。

HTTP錯誤代碼示例:

400 -壞輸入參數。 錯誤信息應該顯示哪個,爲何。

401 -壞或過時的令牌。 這可能發生,若是用戶或Dropbox撤銷或過時一個訪問令牌。 來解決,你應該認證用戶。

403 -壞OAuth請求(錯誤的消費的關鍵,壞nonce,到期時間戳…)。 不幸的是,認證用戶不會幫助。

404 -文件或文件夾沒有找到指定的路徑。

405 -請求方法(通常應該是GET或POST)。

429 -你的應用使太多的請求和速度有限。 429年代在每一個應用或用戶的基礎上能夠觸發。

503 -若是響應包括Retry-After頭,這意味着你的OAuth 1.0應用程序速度有限。 不然,這代表瞬態服務器錯誤,應用程序應該重試請求。

507 -用戶/ Dropbox存儲配額。

5 xx -服務器錯誤。

  1. Dropbox API將數據做爲JSON返回。 若是你收到一個200響應,而後將數據轉換成JSON使用iOS的JSON建成的反序列化。 瞭解更多關於JSON和NSJSONSerialization,看看23章 iOS 5的教程 「使用JSON。」

返回的JSON數據Dropbox將看起來像這樣:

{
    "hash": "6a29b68d106bda4473ffdaf2e94c4b61", "revision": 73052, "rev": "11d5c00e1cf6c", "thumb_exists": false, "bytes": 0, "modified": "Sat, 10 Aug 2013 21:56:50 +0000", "path": "/byteclub", "is_dir": true, "icon": "folder", "root": "dropbox", "contents": [{ "revision": 73054, "rev": "11d5e00e1cf6c", "thumb_exists": false, "bytes": 16, "modified": "Sat, 10 Aug 2013 23:21:03 +0000", "client_mtime": "Sat, 10 Aug 2013 23:21:02 +0000", "path": "/byteclub/test.txt", "is_dir": false, "icon": "page_white_text", "root": "dropbox", "mime_type": "text/plain", "size": "16 bytes" }], "size": "0 bytes" }

因此添加代碼的最後一位是代碼,拿出你感興趣的部分從JSON。 特別是,你想要遍歷的「內容」數組任何「is_dir」設置爲false。

要作到這一點,後添加如下行「TODO 2」評論:

// 1
NSArray *contentsOfRootDirectory = notesJSON[@"contents"];   for (NSDictionary *data in contentsOfRootDirectory) { if (![data[@"is_dir"] boolValue]) { DBFile *note = [[DBFile alloc] initWithJSONData:data]; [notesFound addObject:note]; } }   [notesFound sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2]; }];   self.notes = notesFound;   // 6 dispatch_async(dispatch_get_main_queue(), ^{ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [self.tableView reloadData]; });

這裏有兩個部分:

  1. 你退出的數組對象從「內容」鍵,而後遍歷該數組。 每一個數組條目是一個文件,因此你爲每一個文件建立一個相應的DBFile模型對象。
    DBFile助手類我爲你拿出的信息建立一個文件從JSON字典——快速peek因此你能夠看到它是如何工做的。
    當你完成,你將全部的音符添加到自我。 notes屬性。 設置表格視圖來顯示這個數組的任何條目。

如今您已經表視圖的數據源更新,您須要從新加載表數據。 當你處理異步網絡電話,你要確保更新UIKit在主線程。

聰明的讀者可能會注意到在上面的代碼沒有錯誤處理;若是你感受更(和大多數字節俱樂部的成員都是!)添加一些代碼(以及後續代碼塊中您將添加),將重試的錯誤和警告用戶。

構建和運行您的應用程序,您應該看到文件添加到您的Dropbox文件夾出如今列表中,以下面的示例所示:

file added

這是小事,但它是活生生的證據,你正確地調用Dropbox API。

下一步是把筆記和問題挑戰其餘俱樂部成員,再次使用Dropbox API做爲交付機制。

文章指出經過Dropbox API

在右上角點擊加號,你會看到注意添加/編輯屏幕出現,以下圖所示:

add edit screen

starter應用程序已經創建了經過DBFile模型對象 NoteDetailsViewController prepareForSegue 發送者:。

若是你看一眼這個方法,你會發現NoteViewController設置的 NoteDetailsViewController的 委託。 這種方式,NoteDetailsViewController能夠通知NoteViewController當用戶完成編輯的報告,或取消編輯。

NotesViewController開放。 prepareForSegue m和添加如下行:發送方:,剛剛showNote。 委託=自我;

showNote.session = _session;

NoteDetailsViewController已經有一個 NSURLSession 會話屬性,所以您能夠設置在prepareForSegue:發送方:以前加載。

如今細節視圖控制器將共享相同的 NSURLSession ,因此細節視圖控制器可使用它來讓DropBox API調用。

取消 完成 按鈕已經出如今應用程序;你只須要添加一些邏輯背後保存或取消請注意,在進步。
在NoteDetailsViewController。 米,發現如下行(IBAction)完成:(id)發送者:

// - UPLOAD FILE TO DROPBOX - //
    [self.delegate noteDetailsViewControllerDoneWithDetails:self];

…,代之如下列:

// 1
NSURL *url = [Dropbox uploadURLForPath:_note.path];   // 2 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; [request setHTTPMethod:@"PUT"];   // 3 NSData *noteContents = [_note.contents dataUsingEncoding:NSUTF8StringEncoding];   // 4 NSURLSessionUploadTask *uploadTask = [_session uploadTaskWithRequest:request fromData:noteContents completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;   if (!error && httpResp.statusCode == 200) {   [self.delegate noteDetailsViewControllerDoneWithDetails:self]; } else { // alert for error saving / updating note } }];   // 5 [uploadTask resume];

這實現了全部你須要保存和分享你的筆記。 若是你仔細看看每個評論部分,你會發現代碼以下:

  1. 再次上傳文件Dropbox,您須要使用一個特定的API的URL。 就像以前你須要列出一個目錄中的文件的URL,我已經建立了一個輔助方法爲您生成的URL。 你叫這個。
  2. 接下來是你的老朋友NSMutableURLRequest。 簡單的url和新的api可使用 NSURLRequest 對象,但你須要可變形式符合Dropbox API但願這個請求PUT請求。 設置HTTP方法把信號Dropbox,你想建立一個新文件。
  3. 下一個你從UITextView編碼文本NSData對象。
  4. 如今,你建立的請求和NSData對象,下建立一個你 NSURLSessionUploadTask 和 設置完成處理程序塊。 在成功以後,您調用委託方法noteDetailsViewControllerDoneWithDetails:關閉模式內容。 在生產級應用程序能夠經過一個新的DBFile回委託和同步你的持久數據。 對於本應用程序,您只需刷新NotesViewController新的網絡電話。
  5. 再次,全部任務都建立爲暫停因此你必須打電話給簡歷他們開始。 懶惰的奴才!

構建和運行您的應用程序,點擊加號Notes選項卡。 輸入您的名字 挑戰的名字 字段,輸入一些文本 請注意 場提供了一個挑戰雷,相似於下面的例子:

enter note

當你點擊 完成 ,NoteViewController將返回,列出你的新注意以下所示:

view note

你正式的挑戰,發出挑戰雷;然而,他的朋友在很高的地方,因此你最好把你的最好的遊戲!

可是有一個重要的功能缺失。 你能告訴這是什麼嗎?

點擊包含挑戰的注意;NoteDetailsViewController禮物自己,但注意的是空白的文本。

射線不會發現你的挑戰很威脅若是他不能讀它!

如今,應用程序只調用Dropbox元數據API來檢索文件的列表。 你須要添加一些代碼來獲取注意的內容。

NoteDetailsViewController開放。 m和空白retreiveNoteText實現替換爲如下幾點:

-(void)retreiveNoteText { // 1 NSString *fileApi = @"https://api-content.dropbox.com/1/files/dropbox"; NSString *escapedPath = [_note.path stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];   NSString *urlStr = [NSString stringWithFormat: @"%@/%@", fileApi,escapedPath];   NSURL *url = [NSURL URLWithString: urlStr];   [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;   // 2 [[_session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {   if (!error) { NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 200) { // 3 NSString *text = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; dispatch_async(dispatch_get_main_queue(), ^{ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; self.textView.text = text; });   } else { // HANDLE BAD RESPONSE // } } else { // ALWAYS HANDLE ERRORS :-] // } // 4 }] resume]; }

上面的代碼(無錯誤檢查)在表格下面的備註說明:

  1. 設置請求的URL路徑和文件你但願檢索;/文件端點Dropbox API將返回一個特定的文件的內容。
  2. 建立任務和一個URL指向的數據文件。 這叫應該開始看你通過這個程序很熟悉。
  3. 若是你的響應代碼代表,全部是好的,在主線程上設置textView你前面步驟中檢索的文件內容。 記住,UI更新必須派出主線程。
  4. 一旦初始化任務,調用的簡歷。 這是比之前稍微不一樣的方法,由於簡歷直接被稱爲任務沒有分配任何東西。

構建和運行您的應用程序,在列表中點擊你的挑戰和內容正確顯示在視圖中,以下所示:

note display

你能夠扮演雷和應對挑戰的一部分經過輸入文本注;將盡快更新你的文件 完成

共享應用程序和Dropbox文件夾與代碼的一些朋友,讓他們測試你的應用程序經過添加和編輯筆記之間彼此。 畢竟,字節俱樂部更有趣有不止一我的!

上傳照片與NSURLSessionTask表明

您已經瞭解瞭如何使用 NSURLSession 異步的簡便方法。 可是若是你想關注一個文件傳輸,如上傳一個大文件和顯示一個進度條?

對於這種類型的異步的,耗時的任務你須要實現協議的方法 NSURLSessionTaskDelegate 。 經過實現這種方法,您能夠接收回調函數,當一個任務接收數據並完成接收數據。

您可能已經注意到, PanoPhotos 標籤是空的,當你啓動應用。然而,字節俱樂部的創始成員有本身的慷慨地提供了一些全景照片來填補你的應用。

下載這些 全景照片 咱們一塊兒給你。 解壓縮文件,並將照片目錄複製到你的應用在Dropbox文件夾。 你的文件夾應相似於如下內容:

photos folder

Dropbox核心API能夠提供照片的縮略圖,這聽起來像是完美的用於UITableView細胞。

PhotosViewController開放。 m並將下面的代碼添加到tableView:cellForRowAtIndexPath:剛剛評論說「去縮略圖」:

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSURLSessionDataTask *dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { UIImage *image = [[UIImage alloc] initWithData:data]; photo.thumbNail = image; dispatch_async(dispatch_get_main_queue(), ^{ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; cell.thumbnailImage.image = photo.thumbNail; }); } else { // HANDLE ERROR // } }]; [dataTask resume];

上面的代碼顯示了照片的縮略圖在表視圖單元格…或者至少,目前若是_photoThumbnails數組不是空的。

找到 refreshPhotos 用如下代碼替換它的實現:

- (void)refreshPhotos { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; NSString *photoDir = [NSString stringWithFormat:@"https://api.dropbox.com/1/search/dropbox/%@/photos?query=.jpg",appFolder]; NSURL *url = [NSURL URLWithString:photoDir];   [[_session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response; if (httpResp.statusCode == 200) {   NSError *jsonError; NSArray *filesJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError]; NSMutableArray *dbFiles = [[NSMutableArray alloc] init];   if (!jsonError) { for (NSDictionary *fileMetadata in filesJSON) { DBFile *file = [[DBFile alloc] initWithJSONData:fileMetadata]; [dbFiles addObject:file]; }   [dbFiles sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2]; }];   _photoThumbnails = dbFiles;   dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; [self.tableView reloadData]; }); } } else { // HANDLE BAD RESPONSE // } } else { // ALWAYS HANDLE ERRORS :-] // } }] resume]; }

這很是相似於你以前寫的代碼加載所面臨的挑戰。 這一次,API調用查看 照片 目錄,只請求文件。 jpg格式擴展。

如今_photoThumbnails數組填充,縮略圖將顯示在表視圖和異步更新。

構建和運行您的應用程序切換到PanoPhotos選項卡,縮略圖將加載和顯示以下:

thumbnails

這些照片看起來很好,只是當心的Matthijs code-shredding貓!

上傳PanoPhoto

你的應用能夠下載照片,但它若是它還能夠上傳圖片和顯示上傳的進度。

一個上傳的進步跟蹤, PhotosViewController 必須是一個委託的嗎 NSURLSessionDelegate NSURLSessionTaskDelegate 協議,這樣你就能夠得到進步回調。

修改 PhotosViewController 接口聲明的 PhotosViewController.m 經過添加
NSURLSessionTaskDelegate ,以下:

@interface PhotosViewController ()<UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate, NSURLSessionTaskDelegate>

接下來,添加如下私人財產:

@property (nonatomic, strong) NSURLSessionUploadTask *uploadTask;

上面的指針引用任務對象;這樣,你就能夠訪問對象的成員的進步跟蹤上傳任務。

當用戶選擇照片上傳, didFinishPickingMediaWithInfo 調用 uploadImage: 執行文件上傳。 如今,這個方法是空的——這是你的職責肉出來。

用下面的代碼替換uploadImage::

- (void)uploadImage:(UIImage*)image { NSData *imageData = UIImageJPEGRepresentation(image, 0.6);   // 1 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; config.HTTPMaximumConnectionsPerHost = 1; [config setHTTPAdditionalHeaders:@{@"Authorization": [Dropbox apiAuthorizationHeader]}];   // 2 NSURLSession *upLoadSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];   // for now just create a random file name, dropbox will handle it if we overwrite a file and create a new name.. NSURL *url = [Dropbox createPhotoUploadURL];   NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; [request setHTTPMethod:@"PUT"];   // 3 self.uploadTask = [upLoadSession uploadTaskWithRequest:request fromData:imageData];   // 4 self.uploadView.hidden = NO; [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];   // 5 [_uploadTask resume]; }

這是發生了什麼在上面的代碼中:

  1. 之前,您使用會話設置在initWithCoder和相關的便利方法建立異步任務。 這一次,你用一個NSURLSessionConfiguration只容許一個鏈接到遠程主機,由於你一次處理一個文件上傳過程。
  2. 上傳和下載任務報告信息反饋給他們的表明,您很快就會實現這些。
  3. 在這裏你設置uploadTask屬性使用JPEG圖像從UIImagePicker得到。
  4. 接下來,您顯示UIProgressView PhotosViewController隱藏在。
  5. 啓動任務——呃,對不起,恢復任務。

如今委託已設置,您能夠實現的 NSURLSessionTaskDelegate 更新進度視圖的方法。

將下面的代碼添加到年末PhotosViewController.m:

#pragma mark - NSURLSessionTaskDelegate methods
 
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { dispatch_async(dispatch_get_main_queue(), ^{ [_progress setProgress: (double)totalBytesSent / (double)totalBytesExpectedToSend animated:YES]; }); }

上述委託方法按期報告上傳任務信息返回給調用者。 它還更新 UIProgressView (_progress)來顯示totalBytesSent / totalBytesExpectedToSend比顯示信息(更加)完成百分比。

惟一留下的是表示當上傳任務完成。 添加如下方法PhotosViewController.m結束:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // 1 dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; _uploadView.hidden = YES; [_progress setProgress:0.5]; });   if (!error) { // 2 dispatch_async(dispatch_get_main_queue(), ^{ [self refreshPhotos]; }); } else { // Alert for error } }

這裏沒有太多的代碼,但它執行兩個重要的任務:

  1. 關閉網絡活動指標,而後隱藏_uploadView的清理一旦完成了上傳。
  2. 刷新PhotosViewController包括剛纔上傳的圖片由於你的演示應用程序不是在本地存儲任何東西。 在真實的應用程序,你可能應該在本地存儲或緩存圖像。

構建和運行您的應用程序,導航到PanoPhotos選項卡,點擊相機圖標來選擇一個映像。

select image

 

注意: 若是你使用模擬器來測試應用程序,你用Mac顯然不能拍照,因此就複製一個全景的模擬器和上傳照片。 要作到這一點,確保沒有其餘Xcode項目目前正在鏈接到模擬器和在Xcode中選擇 Xcode \開放開發人員工具\ iOS模擬器。

拖着包括全景照片的發現者的模擬器圖像將在Safari。 而後長按圖像,將圖像保存到照片庫。

選擇圖片上傳後,uploadView顯示在屏幕中間隨着UIProgressView以下所示:

image upload

您可能已經注意到,一個圖像上傳能夠花一些時間因爲「更好的質量比例因子設置上傳任務。 信不信由你,有些用戶在他們的移動設備有點不耐煩! ☺對於那些a類型的個性,你應該提供一個取消的功能若是上傳耗時太長。

上的Cancel按鈕uploadView已經從故事板鏈接起來,因此你只須要實現邏輯清晰地殺死下載。

取代 cancelUpload :在PhotosViewController方法。 用下面的代碼:

- (IBAction)cancelUpload:(id)sender { if (_uploadTask.state == NSURLSessionTaskStateRunning) { [_uploadTask cancel]; } }

取消一個任務同樣容易調用取消方法,您能夠在這裏看到。

如今構建並運行你的應用程序,選擇照片上傳和水龍頭 取消 。 圖像上傳將中止和uploadView隱藏。

就是這樣字節俱樂部完成!

從這裏去哪裏?

這是 完成項目 從這個NSURLSession教程。

若是你作到這一步,那麼恭喜你享受你一生在字節俱樂部會員! 就不要告訴任何Android的傢伙! :你如今應該可以處理任何網絡任務應用程序的需求。

若是你喜歡本教程,您可能想要查看咱們的新書 iOS 7教程 。 這是一個縮寫版的一個29章在這本書中,覆蓋全部的最新最好的api在iOS 7中,你必定會想要知道做爲一名開發人員。

我差點忘了…

/slap <you the reader> have been slapped around a bit with a large trout.

(不要問爲何呵呵!)

若是你有任何問題或評論本教程或NSURLSession通常,請加入如下論壇討論!

相關文章
相關標籤/搜索