注意從雷 :這是一個縮寫版的一章 iOS 7教程 咱們發佈的一部分 iOS 7盛宴 。 咱們但願你能喜歡! git
每個新的iOS版本包含了一些很棒的新的網絡api,和iOS 7也不例外。 在iOS 7中,蘋果推出了 NSURLSession
,這是一套類取代 NSURLConnection
做爲網絡的首選方法。 github
在這NSURLSession教程中,您將學習這個新類是什麼,爲何和應該如何使用它,如何比較以前的,最重要的是:獲得實踐整合成一個真正的應用程序! web
請注意,本教程假設您熟悉基本的網絡概念。 若是你是全新的網絡,你仍然能夠跟隨一切都是一步一步的,但可能會有一些不熟悉的概念,你可能須要查找。 json
你爲何要使用 NSURLSession
嗎? 它帶給你一些新優點和好處: api
NSURLSession
建立,獲得全部背景網絡的好處。 這有助於與電池壽命,支持UIKit多任務和使用相同的委託模型做爲進程內轉移。 NSURLSession
是可配置爲將請求放入容器。 例如,若是您須要設置一個HTTP頭的選擇你只須要這樣作一次,每一個請求的會話將會有相同的配置。 NSURLSession
subclassable,您能夠配置一個會話使用的私有存儲在每一個會話的基礎上。 這容許您有私人存儲對象以外的全局狀態。 改進的認證處理: 身份驗證是在特定的鏈接的基礎上完成的。 當使用 NSURLConnection
若是身份驗證發出挑戰,挑戰爲任意請求會回來,你不會知道請求的挑戰。 與 NSURLSession
,委託處理身份驗證。 數組
NSURLConnection
有一些基於異步阻塞方法,可是不能使用一個委託。 當請求使其做品或失敗,即便須要身份驗證。 與 NSURLSession
你能夠有一個混合的方法,使用基於異步阻塞方法並設置一個委託處理身份驗證。 「哇,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
對於簡單的任務,有一組豐富的額外的功能,當你須要它。
討論網絡代碼沒有徹底不提到AFNetworking框架。 這是一個最流行的框架用於iOS / OS X,創造的輝煌Mattt湯普森。
這就是相同的數據任務的代碼看起來像使用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或其餘格式。
因此您可能想知道若是你應該使用AFNetworking仍是堅持 NSURLSession
。
就我我的而言,我認爲最好是堅持簡單的需求 NSURLSession
——這能夠避免沒必要要的第三方依賴引入您的項目。 新表明,配置和基於任務的API的不少「缺失的功能」AFNetworking添加如今包括在內。
然而,若是你想使用2.0的一些新特性中發現AFNetworking序列化和進一步UIKit集成(除了UIImageView類別),那麼很難反對使用它!
NSURLSession
。 有關更多信息,請參見這篇文章:
在這NSURLSession教程中,您將探索這種新的API經過構建一個筆記和圖片共享應用程序之上Dropbox核心API的絕密組織命名爲字節俱樂部。
因此考慮本教程你正式邀請字節俱樂部! 字節俱樂部的第一條規矩,你可能會問? 沒有人談論字節俱樂部——除了那些很酷的足以閱讀本教程。 絕對不是那些Android用戶;他們終身禁止。 :]
頭在下一節開始構建應用程序,將做爲你的起始字節俱樂部。
請注意,本教程假設您擁有一些基本的熟悉網絡若是iOS在之前的版本中。 頗有幫助若是你使用api NSURLConnection
或 NSURLSession
在過去。 若是你全新的網絡在iOS,您應該檢查咱們的iOS學徒系列初級開發者,而後再繼續學習本教程。
字節俱樂部是獨家的iOS開發者加入分組進行編碼的挑戰。 由於每一個成員這些挑戰來自世界各地的遠程工做,成員也發現它有趣分享全景照片的「戰鬥」。
這裏有一個全景的照片光線的辦公室設置,例如:
在iOS 7中,你能夠經過打開全景照片 照片 並選擇標籤命名 帕諾人 。
若是你喜歡結果,你能夠把它做爲你的鎖定屏幕的壁紙 設置 並選擇 亮度和壁紙\選擇壁紙\個人全景照片 。
固然字節俱樂部有本身的應用程序讓這一切發生。 您可使用應用程序建立編碼挑戰或與其餘成員分享全景照片。 在幕後,這是經過網絡實現,具體地說,經過共享文件Dropbox API。
首先,下載 本教程啓動項目。
這對你啓動項目包括UI預製,這樣你就能夠專一於本教程中的網絡應用程序的一部分。 starter項目還包括一些代碼來處理Dropbox認證,之後你會了解更多。
打開Xcode項目和你的設備或模擬器上運行它。 您應該看到一個屏幕是這樣的:
然而,您將沒法登陸,您必須配置應用程序首先,你要作的。
主要的下一個開放。 故事板,看看這個應用程序的整體設計:
這是一個基本選項卡應用與兩個選項卡:一個用於代碼的挑戰,一個全景照片。 還有一個步驟以前,記錄用戶的應用程序。你設置登陸在您建立Dropbox平臺下面的應用程序。
隨時查看應用程序的其他部分和熟悉有什麼到目前爲止。 你會發現除了受權組件,沒有網絡代碼檢索代碼挑戰或全景照片,那是你的工做!
開始與你的Dropbox應用程序,打開Dropbox位於應用程序控制臺 https://www.dropbox.com/developers/apps
登陸若是您有一個Dropbox賬戶,但若是不是,沒有汗水:建立一個免費的Dropbox賬戶。 若是這是你第一次使用Dropbox API,你須要贊成Dropbox條款和條件。
在法律的東西,選擇建立應用程序選項。 你會面對一系列的問題——提供如下回復
最後,爲應用程序提供一個名稱,無論你選擇什麼,只要它是獨一無二的。 Dropbox將讓你知道若是你選擇了一個名字,已經在使用。 您看到的屏幕應該相似以下:
點擊 建立應用程序 和你的路上!
在下一個屏幕上,您將看到顯示屏幕包含 應用的關鍵 和 應用程序的祕密:
不要關閉這個屏幕;你須要應用程序下一步的關鍵和應用的祕密。
打開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 。 點擊應用程序名,而後單擊啓用額外的用戶按鈕。 會出現一個對話框說你增長了用戶限制。 單擊對話框上的好清楚。 應用程序頁面將如今看起來像下面的:
Dropbox將回顧你的應用程序,以確保它符合他們的指南,若是一切順利的話,他們將打開你的應用程序的API訪問無限的用戶。
在您的應用程序可使用Dropbox API以前,你須要對用戶進行身份驗證。 在Dropbox,這是經過OAuth——一個流行的開源協議,容許安全受權。
本教程的重點是在網絡上,不是OAuth,因此我已經建立了一個小API Dropbox。 m處理大部分的給你。
若是您曾經使用過第三方twitter客戶端應用程序,像TweetBot,那麼你就會熟悉OAuth安裝過程當中從用戶的視角。 OAuth過程幾乎相同的應用程序。
構建和運行您的應用程序,並遵循的步驟登陸。 你會看到一個空白的屏幕上有兩個標籤,一個用於筆記和一個用於PanoPhotos,以下所示:
OAuth身份驗證發生在三個高水平的步驟:
注意: 本教程保持簡潔,咱們不打算詳細Dropbox身份驗證是如何工做的。 然而,若是你想了解更多查看本教程的完整版的一部分 iOS 7教程 。
蘋果公司描述 NSURLSession
做爲一個新類和套類。 有新工具上傳、下載、處理受權和處理HTTP協議的任何東西。
在開始編碼以前,重要的是要有一個好的理解的主要類 NSURLSession
套件以及它們如何一塊兒工做。
一個 NSURLSession
是使用一個 NSURLSessionConfiguration
和一個可選的委託。 在您建立會話而後知足你網絡須要經過建立 NSURLSessionTask的
。
有三種方法來建立一個 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; |
這些只是您能夠配置的一些事情,必定要檢查出一個完整的文檔列表。
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
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]; |
啊哈! 如今這看起來像一些網絡代碼!
NSURLSessionDownloadDelegate
跟蹤下載進度。 因此你獲得一箭雙鵰! (挑戰* *提示)
-URLSession:downloadTask :didWriteData:totalBytesWritten :totalBytesExpectedToWrite: |
這是看起來如何,使用相同的會話從上面:
// 1
NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:[NSURL URLWithString:imageUrl]]; [getImageTask resume]; |
你須要委託實現的一些方法 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
是真正的主力經過網絡完成的東西」。
到目前爲止,您已經看到 NSURLSessionDataTask
和 NSURLSessionDownloadTask
在使用。 來自這兩個任務 NSURLSessionTask
這兩個基類,在這裏你能夠看到:
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
能做到下載文件從遠程服務,暫停和恢復下載。 這個比其餘兩個子類有點不一樣。
這個特性很是有用當俱樂部一個字節位置全景照片下載到你的設備的攝像頭。 你看到一個例子下載任務在上面的代碼片斷下載一個圖像。
上面全部的
上述全部任務建立掛起狀態;在建立一個您須要調用它的恢復方法以下證實:
[uploadTask resume]; |
taskIdentifier屬性容許您將唯一地標識一個任務在一個會話當你管理多個任務。
就是這樣! 如今你知道的主要類 NSURLSession
套房,讓咱們試試。
好吧,這不是《死亡詩社》這是字節俱樂部! 是時候開始看看這個網絡代碼的行動。
您須要一種方法來發送消息到其餘字節俱樂部的成員。 既然你已經創建了一個訪問令牌,下一個步驟是先實例化NSURLSesssion並讓你調用Dropbox API。
添加如下屬性 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解釋上面的代碼:
NSURLSession
。 你不想要激進的緩存或持久性,因此你使用ephemeralSessionConfiguration便利方法,它返回一個會話緩存沒有持久性存儲,餅乾,或憑據。 這是一個「隱私瀏覽」配置。 NSURLSession
使用上面的配置。 這個會議如今準備建立的任何網絡任務,你須要在你的應用程序。
模擬報告被另外一個用戶添加,添加任何你選擇的文本文件的文件夾設置根Dropbox文件夾。 下面的例子顯示了文件 用法 坐在 byteclub Dropbox文件夾:
等到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文件夾。 咱們這是如何工做的一段一段的。
NSURLSession
有方便的方法來輕鬆地建立各類類型的任務。 給你建立一個數據任務爲了執行GET請求URL。 當請求完成後,你的completionHandler塊。 你會添加一些代碼在一個時刻。 這是全部您須要作的開始一個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! } } |
這裏有兩個主要部分:
HTTP錯誤代碼示例:
400 -壞輸入參數。 錯誤信息應該顯示哪個,爲何。
401 -壞或過時的令牌。 這可能發生,若是用戶或Dropbox撤銷或過時一個訪問令牌。 來解決,你應該認證用戶。
403 -壞OAuth請求(錯誤的消費的關鍵,壞nonce,到期時間戳…)。 不幸的是,認證用戶不會幫助。
404 -文件或文件夾沒有找到指定的路徑。
405 -請求方法(通常應該是GET或POST)。
429 -你的應用使太多的請求和速度有限。 429年代在每一個應用或用戶的基礎上能夠觸發。
503 -若是響應包括Retry-After頭,這意味着你的OAuth 1.0應用程序速度有限。 不然,這代表瞬態服務器錯誤,應用程序應該重試請求。
507 -用戶/ Dropbox存儲配額。
5 xx -服務器錯誤。
返回的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]; }); |
這裏有兩個部分:
如今您已經表視圖的數據源更新,您須要從新加載表數據。 當你處理異步網絡電話,你要確保更新UIKit在主線程。
聰明的讀者可能會注意到在上面的代碼沒有錯誤處理;若是你感受更(和大多數字節俱樂部的成員都是!)添加一些代碼(以及後續代碼塊中您將添加),將重試的錯誤和警告用戶。
構建和運行您的應用程序,您應該看到文件添加到您的Dropbox文件夾出如今列表中,以下面的示例所示:
這是小事,但它是活生生的證據,你正確地調用Dropbox API。
下一步是把筆記和問題挑戰其餘俱樂部成員,再次使用Dropbox API做爲交付機制。
在右上角點擊加號,你會看到注意添加/編輯屏幕出現,以下圖所示:
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]; |
這實現了全部你須要保存和分享你的筆記。 若是你仔細看看每個評論部分,你會發現代碼以下:
NSURLRequest
對象,但你須要可變形式符合Dropbox API但願這個請求PUT請求。 設置HTTP方法把信號Dropbox,你想建立一個新文件。 NSURLSessionUploadTask
和 設置完成處理程序塊。 在成功以後,您調用委託方法noteDetailsViewControllerDoneWithDetails:關閉模式內容。 在生產級應用程序能夠經過一個新的DBFile回委託和同步你的持久數據。 對於本應用程序,您只需刷新NotesViewController新的網絡電話。 構建和運行您的應用程序,點擊加號Notes選項卡。 輸入您的名字 挑戰的名字 字段,輸入一些文本 請注意 場提供了一個挑戰雷,相似於下面的例子:
當你點擊 完成 ,NoteViewController將返回,列出你的新注意以下所示:
你正式的挑戰,發出挑戰雷;然而,他的朋友在很高的地方,因此你最好把你的最好的遊戲!
可是有一個重要的功能缺失。 你能告訴這是什麼嗎?
點擊包含挑戰的注意;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]; } |
上面的代碼(無錯誤檢查)在表格下面的備註說明:
構建和運行您的應用程序,在列表中點擊你的挑戰和內容正確顯示在視圖中,以下所示:
你能夠扮演雷和應對挑戰的一部分經過輸入文本注;將盡快更新你的文件 完成 。
共享應用程序和Dropbox文件夾與代碼的一些朋友,讓他們測試你的應用程序經過添加和編輯筆記之間彼此。 畢竟,字節俱樂部更有趣有不止一我的!
您已經瞭解瞭如何使用 NSURLSession
異步的簡便方法。 可是若是你想關注一個文件傳輸,如上傳一個大文件和顯示一個進度條?
對於這種類型的異步的,耗時的任務你須要實現協議的方法 NSURLSessionTaskDelegate
。 經過實現這種方法,您能夠接收回調函數,當一個任務接收數據並完成接收數據。
您可能已經注意到, PanoPhotos 標籤是空的,當你啓動應用。然而,字節俱樂部的創始成員有本身的慷慨地提供了一些全景照片來填補你的應用。
下載這些 全景照片 咱們一塊兒給你。 解壓縮文件,並將照片目錄複製到你的應用在Dropbox文件夾。 你的文件夾應相似於如下內容:
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選項卡,縮略圖將加載和顯示以下:
這些照片看起來很好,只是當心的Matthijs code-shredding貓!
你的應用能夠下載照片,但它若是它還能夠上傳圖片和顯示上傳的進度。
一個上傳的進步跟蹤, 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]; } |
這是發生了什麼在上面的代碼中:
如今委託已設置,您能夠實現的 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 } } |
這裏沒有太多的代碼,但它執行兩個重要的任務:
構建和運行您的應用程序,導航到PanoPhotos選項卡,點擊相機圖標來選擇一個映像。
拖着包括全景照片的發現者的模擬器圖像將在Safari。 而後長按圖像,將圖像保存到照片庫。
選擇圖片上傳後,uploadView顯示在屏幕中間隨着UIProgressView以下所示:
您可能已經注意到,一個圖像上傳能夠花一些時間因爲「更好的質量比例因子設置上傳任務。 信不信由你,有些用戶在他們的移動設備有點不耐煩! 對於那些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通常,請加入如下論壇討論!