2016-11-21 67 views
0

我对Swift(新手)很新颖,但对C#有很好的使用经验。Swift3使用Alamofire和返回字典下载JSON数据

我想要做的是使用Alamofire从API下载JSON数据并将字典返回给调用方法。 我遇到的问题不会将数据返回给调用函数。我假设我的问题是下载是异步的。

这是我下载数​​据的函数的代码。

import UIKit 
import Alamofire 

class SharedFunctions { 


    class func downloadWeatherData(url: String, completed: @escaping DownloadComplete) -> Dictionary<String, AnyObject>? { 


     let currentWeatherURL = URL(string: url)! 

     var workingDict: Dictionary<String, AnyObject>? = nil 

     Alamofire.request(currentWeatherURL).responseJSON { 
      response in 
      let result = response.result 

      workingDict = result.value as? Dictionary<String, AnyObject> 

      completed() 

     } 

     return workingDict 

    } 
} 

我具有存储在一个单独的常量类这种类型别名。

typealias DownloadComplete =() ->() 

我的调用函数,当它碰到if let dict时,代码将继续执行而没有做太多的事情。这个函数被视图控制器代码调用。

func downloadWeatherDetails(completed: @escaping DownloadComplete) 
{ 
     if let dict = SharedFunctions.downloadWeatherData(url: CURRENTWEATHERURL, completed: completed) { 

      if let name = dict["name"] as? String { 
       self._cityName = name.capitalized 
      } 

     } 
    completed() 
} 

我这是工作的旧代码,我不得不调用Alamofire从downloadWeatherDetails函数被调用,把它做工精细,数据恢复回VC下载完成时。

回答

0

您需要更改您的功能像这样 -

typealias DownloadComplete = Dictionary<String, Any> 

    func downloadWeatherData(url: String, completion: (DownloadComplete) -> Void) { 

     //Do your process here 
     Alamofire.request(url).responseJSON { 
     response in 
      // Finish process here 
      switch response.result { 
      case .success: 
      completion(response.result.value as? Dictionary<String, Any>) 
      case .failure(let error): 
      completion([:]) 
      print(error) 
      } 

     } 

    } 

    //MARK: - Call function 
    downloadWeatherData(url: "your url here") { (DownloadComplete) in 
     //Do something with data 
     print(DownloadComplete) 
    } 
2

这里有两个问题:

  1. downloadWeatherData试图返回异步返回的数据。它不应该返回任何东西,而只是将数据传递回闭包中。

  2. downloadWeatherDetails将一个闭包参数直接传递给downloadWeatherData,但也(a)试图提供自己的闭包给该方法;和(b)更新财产。

    它应该可能只是建立一些模型对象,并再次通过闭包传回。它也不应该更新一个属性。

所以,让我们退后一步。要通过字典结果反馈,更新封闭的typealias相应:

typealias DownloadComplete = ([String: Any]?) -> Void 

顺便说一句,我用的是[KeyType: ValueType]语法,这比Dictionary<KeyType, ValueType>更简洁,但可以使用其他的语法,如果你真正想要的。另外请注意,我将闭包的参数设置为可选的(这样可以区分成功的呼叫和失败)。

然后downloadWeatherData很简单:

/// Return the dictionary returned by web service. 
/// 
/// - Parameters: 
/// - url:  URL of the web service. 
/// - completed: The closure that's called when the asynchronous call finishes. If there was an error, the dictionary will be `nil`. 
class func downloadWeatherData(url: String, completed: @escaping DownloadComplete) { 
    Alamofire.request(urlString).responseJSON { response in 
     completed(response.result.value as? [String: Any]) 
    } 
} 

通过另一种方法,downloadWeatherDetails的目的,目前还不太清楚。您似乎试图同时更新某个属性并调用闭包。为了保持干净,我建议你做一个或另一个,但不是两个。

例如,我可以想像一些模型对象:

struct WeatherReport { 
    let city: String 
    let low: Float 
    let high: Float 
} 

而且downloadWeatherDetails可以提取的信息,也许是构建模型对象的一些关键件(我已经改名为方法,因此):

/// Build `WeatherReport` object and pass it back in the closure. 
/// 
/// - Parameter completed: The closure that will be called when the method finishes. 

func downloadWeatherReport(completed: @escaping (WeatherReport?) -> Void) { 
    SharedFunctions.downloadWeatherData(url: currentWeatherUrl) { dictionary in 
     guard let city = dictionary?["name"] as? String, let low = dictionary?["low"] as? Float, let high = dictionary?["high"] as? Float else { 
      completed(nil) 
      return 
     } 

     completed(WeatherReport(city: city, low: low, high: high)) 
    } 
} 

现在,我不知道该模型对象是否捕获了所有你想要的东西。同样,我不知道你的字典中有什么关键字。但它说明了这个想法:提取构建模型对象所需的信息,并通过闭包传回(不是return语句)。

反正我假设的例子继续,然后我可以做这样的事情,这将更新UI,也许在viewDidLoad或按钮上的水龙头调用:

downloadWeatherReport { weatherReport in 
    guard let weatherReport = weatherReport else { 
     // handle error here 
     return 
    } 

    // update some model property 

    self.weatherReport = weatherReport 

    // and update the UI, too 

    let formatter = NumberFormatter() 
    self.cityLabel.text = weatherReport.city 
    self.lowLabel.text = formatter.string(from: NSNumber(value: weatherReport.low)) 
    self.highLabel.text = formatter.string(from: NSNumber(value: weatherReport.high)) 
} 

但不迷路在我的示例的细节中,而是集中于带回家的消息,即在处理异步方法时,不要尝试立即返回数据或更新属性,而是通过闭包传回数据。让最终调用者负责更新模型和UI。