2014-07-09 20 views
22

我想給我們一個返回一些json數據的RESTful API。我想封裝創建HTTP請求的代碼,並在自己的方法中設置標題,這樣我就可以通過輸入url String來調用它,然後讓該方法返回一個JSON對象。如何在Swift中使用completionHandler Closure?

在下面的代碼片段中,我已經創建了請求對象並設置了標頭,並且我調用了該變量「req」。我沒有聲明任何名爲data,response或error的對象。我有以下的代碼,正確打印出一個JSON對象

let sesh = NSURLSession.sharedSession() 
    let dataTask = sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error) in 
     var jsonError : NSError? 
     let jsonBlob = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &jsonError) 
     println(jsonBlob) 
     }); 

    dataTask.resume() 

因此,這裏是我的問題。我怎樣才能讓這個completionHandler塊能夠返回類型爲「AnyObject!」的jsonBlob?如果我稍微修改代碼,如下所示:

let sesh = NSURLSession.sharedSession() 
    let dataTask = sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error) -> AnyObject! in 
     var jsonError : NSError? 
     let jsonBlob : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &jsonError) 
     return jsonBlob 
     }); 

    dataTask.resume() 

程序將無法正常編譯調用dataTaskWithRequest:completionHandler給出了一個編譯器警告說:

Could not find an overload for 'dataTaskWithRequest' that accepts the supplied arguments 

我不明白這一點。我使用的是正確的語法返回關閉,在此頁面雨燕文檔中給出:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

+0

爲什麼要返回數據?它應該返回到哪裏?目前還不清楚你想要做什麼 - 完成處理程序塊可能不會返回任何內容。 – jtbandes

+0

您希望將什麼信息發回給主叫方?你的完成處理程序在這裏結束程序。 – holex

+0

@jtbandes我需要使用Coinbase的API進行GET請求,然後從返回的JSON對象中提取數據。現在,完成塊運行並返回JSON,但一旦塊結束,響應數據就會丟失。我需要使用來自JSON響應對象的一些數據創建一個String對象,並讓它持續超出該塊的生命。從URL會話文檔我認爲我必須實現一些NSURLSessionDataDelegate協議,一旦返回響應就會觸發它們。它是否正確?儘管我寧願用一個簡單的完成塊來返回東西。 – almel

回答

33
func getSomething(callback: (Array<AnyObject>) ->()) { 
    var dataTask = NSURLSessionDataTask() 
    dataTask = session.dataTaskWithRequest(request) { (data, response, error) in 
     if (error == nil) { 
      var callbackArray = Array<MyObject>() 
      let responseDict = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary 
      let response = responseDict.objectForKey("response_key") as NSDictionary 
      let array = response.objectForKey("array_key") as NSArray 

      for item: AnyObject in array { 
       var arrayItem = MyObject(dict: item as NSDictionary) 
       callbackArray.append(arrayItem) 
      } 

      callback(callbackArray) 
     } else { 
      // handle an error 
     } 
    } 
    dataTask.resume() 
} 

然後,你可以這樣做:

getSomething() { (response) in 
    if let responseArray = response as? Array<MyObject> { 
     self.somethings = responseArray 
    } 
} 
+0

我很困惑,不應該將'request'提供給'getSomething',否則這個函數將始終具有相同的'request',因爲它沒有將它作爲參數來使用......還可以解釋什麼是問題,可能會添加一些評論 – Honey

+0

@Honey與回調你只是真正感興趣的是從服務返回的響應。如果因爲任何原因需要請求,那麼只需返回請求對象。 – fuzz

2

完成處理程序不能返回任何東西,因爲你必須提供封閉必須的返回類型Void而不是AnyObject !.

func dataTaskWithRequest(_ request: NSURLRequest!, 
    completionHandler completionHandler: ((NSData!, 
           NSURLResponse!, 
           NSError!) -> Void)!) -> NSURLSessionDataTask! 
4

你看here,將dataTaskWithRequest:completionHandler:有沒有預期的返回值完成處理。

completion handler's interface

這意味着NSURLSession實例不要指望任何值從你來調用此方法後進行;換句話說:你完成關閉(或阻止,如果你喜歡)在這裏結束程序。

目前還不清楚爲什麼你想通過完成處理程序發回任何東西給來電者。

0

我遇到了類似的問題,試圖基於內容從CloudKit拖着以更新DB中央信息時就來了。用於提取CK數據的模式都具有這些不允許返回值的異步完成處理程序。

因爲我希望能夠在不同的上下文中重複使用類似的代碼,所以我將CK調出分離到它們自己的類中,並且定義了一個委託協議,使我的核心類符合。在完成處理程序中,我將從CK調用中檢索到的數據發回到我希望通過委託方法存儲的位置。

簡單易行。

相關問題