2015-04-02 161 views
0

我正在開發我的第一個iPhone應用程序,我正在調用API以返回一些JSON,它填充了我的UI的不同元素。目前我已經在助手類中實現了一個同步方法,我在viewDidLoad方法中調用該方法。異步json請求Objective C

-(NSDictionary*) dataRequest: (NSString*)url withMethod:(NSString*)method 
{ 

NSError *e; 
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
[request setURL:[NSURL URLWithString:url]]; 
[request setHTTPMethod:method]; 
NSURLResponse *requestResponse; 
NSData *requestHandler = [NSURLConnection sendSynchronousRequest:request returningResponse:&requestResponse error:nil]; 
NSDictionary *json = [NSJSONSerialization JSONObjectWithData: requestHandler options: NSJSONReadingMutableContainers error: &e]; 
return json; 

} 

這裏的問題是我鎖我的UI,我試圖以異步方式實現這一點,但得到的數據返回後不久代碼試圖填充UI元素是什麼來實現異步調用最好的,正確的方法和用正確的數據填充我的UI元素?

回答

4

預計數據在請求發生後很長時間才返回(long,相對於發送請求後幾乎即時執行下一行代碼)。訣竅是延遲UI的更新,直到請求完成。

// optionally update the UI to say 'busy', e.g. placeholders or activity 
// indicators in parts that are incomplete until the response arrives 
[NSURLConnection sendAsynchronousRequest:request 
            queue:[NSOperationQueue mainQueue] 
         completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
    // optionally update the UI to say 'done' 
    if (!error) { 
     NSDictionary *json = [NSJSONSerialization JSONObjectWithData: requestHandler options: NSJSONReadingMutableContainers error: &e]; 
     // update the UI here (and only here to the extent it depends on the json) 
    } else { 
     // update the UI to indicate error 
    } 
}]; 

更抽象地 - 更正確地說 - 考慮到被抓取的數據可能是應用模型的一部分。從服務器獲取只是模型更改的一個原因。當模型由於任何原因而改變時,無論是通過用戶操作還是這個獲取或其他事件,視圖控制器的工作都是要觀察它改變,並告訴視圖更新。

+1

感謝您的建議和代碼片段,我已經成功地實現了我的目標! – JKX 2015-04-06 18:21:05

+0

[NSURLConnection sendAsynchronousRequest]已在iOS 9中棄用。建議使用NSURLSession。 – Nate4436271 2016-08-16 20:15:23

0

有些情況下,當同步請求有意義時,但如果視圖控制器在同步請求完成時等待(阻塞主線程),則不適用。我寫了一篇博文來幫助深入解答這個問題:http://jasoncross-ios-development.blogspot.com/2015/04/asynchronous-json-requests-in-objective.html。這篇文章還討論了從iOS服務器的Web服務器中消耗JSON的其他問題:在不同情況下需要考慮哪些設計模式。

iOS開發中最常見的模式之一是顯示源自Web Service並通過JSON傳輸的數據。本文討論數據的同步和異步讀取以及其他相關設計模式。

同步和異步http請求有什麼區別?在同步http請求中,當前正在執行的代碼「阻塞」(停止並等待)直到請求結束。如果此代碼位於主線程中,則在進行網絡通話時,該應用程序將顯示爲凍結並斷開。這是一個壞主意,違背最佳實踐,應該始終避免。

相比之下,異步http請求允許當前執行的代碼在啓動請求和請求運行時繼續執行。一旦請求完成,代碼「回報」給一個監聽器。在NSURLConnection sendAsynchronousRequest:queue:completionHandler:的情況下,偵聽器是作爲方法參數傳入塊的方法的調用者。在主線程發出網絡請求的情況下,用戶界面不鎖定,應用程序繼續響應用戶手勢,並且是公認的最佳做法。

簡而言之,就是你需要知道的一點:使用異步方法。但是這引出了一個問題:爲什麼同步方法甚至可用,如果它永遠不會被使用?答案是,在提出同步請求時有很多場景是有意義的。詳細說明這些情景中的一部分包括博客帖子的其餘部分。

考慮使用「服務層」,使請求如下:

模型類。這些通常鏡像服務層的JSON對象 。這些類瞭解API並進行網絡調用以獲取JSON。當網絡調用完成時,JSON被轉換爲本地模型類(Objective-C對象)。 視圖控制器。這些類處理用戶交互,並根據需要從服務層請求數據。

如果您的iOS應用程序只需要提取一次數據而不關心更新,則服務層可以執行異步請求,並在請求完成時使用塊更新調用者。主叫方可以要求數據服務層按如下:

[serviceLayer fetchDataFromAPIWithResponseBlock:^(NSArray * arrayOfObjects, NSError *error) { 

if (nil != error) { 
    // deal with error appropriately 
} 
else if (nil != arrayOfObjects) { 
    // update the user interface 
} 

}]; 

但是,如果你的應用涉及改變,無論是服務器或客戶端上的數據,那麼你會想辦法來協調模式的轉變並更新了用戶界面。在這種情況下,您應該考慮使用委託設計模式或觀察者設計模式。如果使用委託模式,則視圖控制器將成爲服務層的委託。當模型數據發生變化時,服務層會通知委託人。在這種情況下,服務層可以使用同步請求,因爲View Controller在等待從服務層回聽時未阻塞。實現委託模式的替代方法是使用NSNotificationCenter通知視圖控制器何時更改模型數據。使用委託模式和通知之間最大的決定因素是在模型數據更改時需要通知多少個視圖控制器。如果只有一個視圖控制器,它可以作爲一個委託。如果有多個視圖控制器,它們都可以通過通知來通知。

如果正在更改模型對象的各個屬性(可能來自iOS應用程序中的其他位置),那麼您應該考慮使用鍵值觀察(KVO)在模型更改時更新視圖。

更深入的討論可以在上面提到的博客文章中找到。