无法在swift中访问闭包之外的数据

时间:2017-06-16 19:29:22

标签: swift swift3

我试图从swift 3中的闭包中提取一个数组,它不适合我。我在WeatherGetter类中有我的JSON解析器,我在viewcontroller.swift视图中调用它如何将weather_data数组分配给一些外部变量?

class WeatherGetter {

    func getWeather(_ zip: String, startdate: String, enddate: String, completion: @escaping (([[Double]]) -> Void)) {
        // This is a pretty simple networking task, so the shared session will do.
        let session = URLSession.shared

        let string = "Insert API address"

        let url = URL(string: string)
        var weatherRequestURL = URLRequest(url:url! as URL)
        weatherRequestURL.httpMethod = "GET"


        // The data task retrieves the data.
        let dataTask = session.dataTask(with: weatherRequestURL) {
            (data, response, error) -> Void in
            if let error = error {
                // Case 1: Error
                // We got some kind of error while trying to get data from the server.
                print("Error:\n\(error)")
            }
            else {
                // Case 2: Success
                // We got a response from the server!
                do {
                    var temps = [Double]()
                    var winds = [Double]()
                    let weather = try JSON(data: data!)
                    //print(weather)
                    let conditions1 = weather["data"]
                    let conditions2 = conditions1["weather"]
                    let count = conditions2.count
                    for i in 0...count-1 {
                        let conditions3 = conditions2[i]
                        let conditions4 = conditions3["hourly"]
                        let count2 = conditions4.count
                        for j in 0...count2-1 {
                            let conditions5 = conditions4[j]
                            let tempF = conditions5["tempF"].doubleValue
                            let windspeed = conditions5["windspeedKmph"].doubleValue
                            //temps.updateValue(tempF, forKey: "\(date)//\(j)")
                            temps.append(tempF)
                            winds.append(windspeed)
                        }
                    }
                    //print(temps)
                    //print(winds)
                    completion([temps, winds])

                }
                catch let jsonError as NSError {
                    // An error occurred while trying to convert the data into a Swift dictionary.
                    print("JSON error description: \(jsonError.description)")
                }
            }
        }

        // The data task is set up...launch it!

        dataTask.resume()
    }


}

override func viewDidLoad() {
    super.viewDidLoad()

    let weather = WeatherGetter()

    weather.getWeather("13323", startdate: "2016-10-01", enddate: "2017-04-30"){(weather_data) -> Void in
        print(weather_data[1])
    }

        //Do your stuff with isResponse variable.
    }

2 个答案:

答案 0 :(得分:0)

您可以将它分配给类属性:

var weatherData: [[Double]]()

override func viewDidLoad() {
    super.viewDidLoad()

    let weather = WeatherGetter()

    weather.getWeather("13323", startdate: "2016-10-01", enddate: "2017-04-30"){(weather_data) -> Void in
        self.weatherData = weather_data
        // reload or display data
    }
}

您需要记住网络请求需要一些时间,所以这就是为什么一旦您知道收到响应就会调用reloadData之类的东西。

比如说,网络响应需要100毫秒才能响应。到数据响应时,viewDidLoad中的所有代码很可能都会完全完成。因此,您需要在收到数据时对其进行响应。如果您的移动信号不良,可能需要更长时间。

这就是你使用回调/闭包的原因。它们在操作完成时被调用

<强>更新

getWeather中的代码为我显示了多个错误,不允许我按原样运行它。

我设法通过略微修改代码和评论来获得天气API的响应。这里的主要问题是您没有将JSON数据转换为特定类型。

    // The data task retrieves the data.
    let dataTask = session.dataTask(with: weatherRequestURL) {
        (data, response, error) -> Void in

        guard error == nil, let data = data else {
            print("ERROR")
            return
        }

        // Case 2: Success
        // We got a response from the server!
        do {
            var temps = [Double]()
            var winds = [Double]()
            if let weather = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:AnyObject] {

                if let conditions1 = weather["data"] as? [String:AnyObject] {
                    print(conditions1)
                }

            }
        } catch let jsonError {
            // An error occurred while trying to convert the data into a Swift dictionary.
            print("JSON error description: \(jsonError)")
        }

    }

    dataTask.resume()

在上面的代码中看到我如何在投射他们的类型时可选地解包值。这是您在整个代码中需要做的事情,并检查您在整个过程中的每一步都获得正确的数据。不幸的是,API响应对我来说太大了。

Unwrapping JSON Swift

Swift Closures

iOS Networking with Swift - 这是一个我强烈推荐的免费课程。这就是我学习iOS网络的方式。

答案 1 :(得分:0)

如@Scriptable所述,响应处理需要一段时间,因为它是异步的。您可以做的是添加OperationQueue.main.addOperation以将当前进程分配给主队列。这将优先处理您的网络响应。您也可以将reloadData放在此部分中。

var weatherData: [Double]()

override func viewDidLoad() {
super.viewDidLoad()

    let weather = WeatherGetter()

    OperationQueue.main.addOperation { 
        weather.getWeather("13323", startdate: "2016-10-01", enddate: "2017-04-30"){(weather_data) -> Void in
        print(weather_data[1])
        // reloadData()
        }
    }
 }