无法从Swift 3中的dataTask中获取JSON数据

时间:2016-11-08 02:50:01

标签: ios json swift

第一篇文章,所以要温柔。我正在玩Swift 3,Xcode 8.1中获取JSON数据。我专门从http://forecast.weather.gov/MapClick.php?lat=38.9782&lon=-76.4933&FcstType=json获取数据。我的守则如下:

    private func getWeatherData(url:URL) -> (currentObservation:Dictionary<String, AnyObject>, currentData:Dictionary<String, AnyObject>) {
    var currentObservation:Dictionary = [:] as Dictionary<String, AnyObject>
    var currentData:Dictionary = [:] as Dictionary<String, AnyObject>
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print ("Error retrieving URLSession")
        }
        else
        {
            if let content = data
            {
                do
                {
                    let JSONData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject

                    if let observation = JSONData["currentobservation"] as? Dictionary<String, AnyObject> {
                        currentObservation = observation
                        print("currentObservation inside of task: \(currentObservation)\n\n")
                    }

                    if let data = JSONData["data"] as? Dictionary<String, AnyObject> {
                        currentData = data
                        print("currentData inside of task: \(currentData)")
                    }

                }
                catch
                {
                    print("Error in trying JSONSerialization")

                }

            }
        }
    }

    task.resume()

    print("currentObservation outside of task: \(currentObservation) \n\n")
    print("currentData outside of task: \(currentData)")

    return (currentObservation , currentData)

}

我得到的输出是:

currentObservation outside of task: [:] 


currentData outside of task: [:]
currentObservation: [:] 


currentData: [:]
currentObservation inside of task: ["state": MD, "name": Annapolis,     United States Naval Academy, "longitude": -76.49, "elev": 3, "Relh": 79, "WindChill": NA, "Weather": Fair, "Altimeter": 1028.7, "latitude": 38.99, "Temp": 46, "SLP": 30.37, "id": KNAK, "timezone": EST, "Weatherimage": nsct.png, "Windd": 0, "Winds": 0, "Visibility": 10.00, "Gust": 0, "Dewp": 40, "Date": 7 Nov 20:54 pm EST]


currentData inside of task: ["hazard": <__NSArrayM 0x60800005a520>(
Frost Advisory, Hazardous Weather Outlook ), "weather": <__NSArrayM 0x60800005a490>(
Clear then Areas Frost, Areas Frost then Sunny,
Partly Cloudy then Slight Chance Showers, etc.(edited for brevity)]

我正在获取JSON数据响应,但我似乎无法保留数据。

我对几件事感到困惑。首先,为什么URLSession.shared.dataTask之外的print语句打印在那些内部之前?

此外,&#34; currentObservation&#34;的打印陈述和&#34; currentData&#34;在函数外部调用,它们在URLSession.shared.dataTask内部之前打印。那是为什么?

最后,最重要的是,为什么JSON数据不能脱离URLSession.shared.dataTask块?

任何见解都会有所帮助。感谢。

编辑: 这是我现在的代码,基于Vinodh的回复。当我打印时,currentObservation和currentData仍为空。

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    var currentObservation:Dictionary = [:] as Dictionary<String, AnyObject>
    var currentData:Dictionary = [:] as Dictionary<String, AnyObject>

    let serverURL = URL(string:"http://forecast.weather.gov/MapClick.php?lat=38.9782&lon=-76.4933&FcstType=json")
    getWeatherData(serverURL: serverURL!, completion: { serverResponse in
        if let observation = serverResponse["currentobservation"] as? Dictionary<String, AnyObject> {
            currentObservation = observation
            print("currentObservation inside of task: \(currentObservation)\n\n")
        }

        if let data = serverResponse["data"] as? Dictionary<String, AnyObject> {
            currentData = data
            print("currentData inside of task: \(currentData)\n\n")
        }
    })

    print("currentObservation outside of task: \(currentObservation)\n\n")
    print("currentData outside of task: \(currentData)")



}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


private func getWeatherData(serverURL:URL, completion:@escaping (AnyObject) ->()){
    let task = URLSession.shared.dataTask(with: serverURL) { (data, response, error) in
        if error != nil {
            print ("Error retrieving URLSession")
        }
        else
        {
            if let content = data
            {
                do
                {
                    let JSONData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject

                    completion(JSONData)

                }
                catch
                {
                    print("Error in trying JSONSerialization")

                }

            }
        }
    }

    task.resume()


}

}

是的,我知道我不应该在违反MVC的ViewController中做这一切,但我只是试图让它在添加数据模型和控制器的复杂性之前使其工作,如以及UI。感谢。

2 个答案:

答案 0 :(得分:0)

首先,URLSession.shared.dataTask闭包内的代码实际上并没有在主线程中执行,一旦你调用task.resume()就会调用它,它会在后台运行,因此你在外面执行的所有打印都是它将首先调用,因为task尚未完成,这就是为什么内部的打印currentObservation inside of task将在

之后被调用

其次,你没有使用代码块的任务响应OUTSIDE,想象它是这样的:创建任务 - &gt;恢复任务 - &gt;网络请求.... - &gt;完成代码关闭,你必须执行代码涉及完成代码闭包中的响应,这是持有print currentObservation inside of task

的部分

答案 1 :(得分:0)

你的关闭不好。请更改如下以获得适当的回复。

服务电话方式:

   private func getWeatherData(serverURL:URL ,completion:@escaping (AnyObject) ->()){
            let task = URLSession.shared.dataTask(with: serverURL) { (data, response, error) in
                if error != nil {
                    print ("Error retrieving URLSession")
                }
                else
                {
                    if let content = data
                    {
                        do
                        {
                            let JSONData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject

                            completion(JSONData)        

                        }
                        catch
                        {
                            print("Error in trying JSONSerialization")

                        }

                    }
                }
            }

            task.resume()


        }

响应解析:

var currentObservation:Dictionary = [:] as Dictionary<String, AnyObject>
        var currentData:Dictionary = [:] as Dictionary<String, AnyObject>

        let serverURL = URL(string:"http://forecast.weather.gov/MapClick.php?lat=38.9782&lon=-76.4933&FcstType=json")
        getWeatherData(serverURL: serverURL!, completion: { serverResponse in
            if let observation = serverResponse["currentobservation"] as? Dictionary<String, AnyObject> {
                currentObservation = observation
                print("currentObservation inside of task: \(currentObservation)\n\n")
            }

            if let data = serverResponse["data"] as? Dictionary<String, AnyObject> {
                currentData = data
                print("currentData inside of task: \(currentData)")
            }
        })