在Swift中解析JSON,AnyObject类型 [英] Parse json in Swift, AnyObject type

查看:73
本文介绍了在Swift中解析JSON,AnyObject类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解析json,但是我在数据类型上遇到了一些困难,尤其是AnyObject类型+向下转换.

I'm trying to parse a json but I have some difficulties with the data types and notably the AnyObject type + downcasting.

让我们考虑以下json(它是完整json的一部分).

Let's consider the following json (it's an extract of a full json).

{  "weather":
   [
      {
         "id":804,
         "main":"Clouds",
         "description":"overcast clouds",
         "icon":"04d"
      }
   ],
}

对我来说,json可以描述如下:

To me, the json can be described as follow :

- json: Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
    - "weather": Array of type [AnyObject] (or NSArray)
         - Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)

我的json是AnyObject类型! (我使用JSONObjectWithData从URL获取JSON).

My json is of type AnyObject! (I use JSONObjectWithData to get the JSON from a URL).

然后我想访问天气词典.这是我写的代码.

I then want to access the weather Dictionary. Here is the code I wrote.

var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError)

if let dict = json as? [String: AnyObject] {
 if let weatherDictionary = dict["weather"] as? [AnyObject] {
      // Do stuff with the weatherDictionary
    }
}

这是我遇到的错误

Playground execution failed: error: <EXPR>:28:56: error: '[AnyObject]' is not a subtype of '(String, AnyObject)'
        if let weatherDictionary = dict["weather"] as? [AnyObject] {

我不明白为什么将dict ["weather"]与(String,AnyObject)而不是AnyObject的子类型进行比较.

I don't understand why dict["weather"] is compared to a subtype of (String, AnyObject) and not AnyObject.

我将字典声明为[String:AnyObject],所以我使用String键访问一个值,我应该有一个AnyObject,不是吗?

I declared my dictionary as [String: AnyObject], so I i access a value using the String key, I should have an AnyObject, no ?

如果我使用NSDictionary而不是[String:AnyObject],它将起作用.

If I use NSDictionary instead of [String: AnyObject], it works.

如果我使用NSArray而不是[AnyObject],那么它将起作用.

If I use NSArray instead of [AnyObject], it works.

- The Xcode 6 beta 3 release notes tell that "NSDictionary* is now imported from Objective-C APIs as [NSObject : AnyObject].".
- And the Swift book: "When you bridge from an NSArray object to a Swift array, the resulting array is of type [AnyObject]."

编辑

我忘了强迫解开字典["weather"]!.

I forgot to force unwrapping the dict["weather"]!.

if let dict = json as? [String: AnyObject] {
    println(dict)
       if let weatherDictionary = dict["weather"]! as? [AnyObject] {
            println("\nWeather dictionary:\n\n\(weatherDictionary)")
            if let descriptionString = weatherDictionary[0]["description"]! as? String {
                println("\nDescription of the weather is: \(descriptionString)")
        }
    }
}

请注意,我们应该仔细检查第一个Optional的存在.

Note that we should double check for the existence of the first Optional.

if let dict = json as? [String: AnyObject] {
    for key in ["weather", "traffic"] {
        if let dictValue = dict[key] {
            if let subArray = dictValue as? [AnyObject] {
                println(subArray[0])
            }
        } else {
            println("Key '\(key)' not found")
        }
    }
}

推荐答案

这对我来说在操场上和使用env xcrun swift

This works fine for me in the playground and in the terminal using env xcrun swift

已更新为SWIFT 4和可编码

UPDATED FOR SWIFT 4 AND CODABLE

这是一个使用Codable协议的Swift 4示例.

Here is a Swift 4 example using the Codable protocol.

var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"

struct Weather: Codable {
    let id: Int
    let main: String
    let description: String
    let icon: String
}

struct Result: Codable {
    let weather: [Weather]
}

do {
    let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!)
    print(weather)
}
catch {
    print(error)
}

已为SWIFT 3.0更新

UPDATED FOR SWIFT 3.0

我已经更新了Swift 3的代码,还展示了如何将已解析的JSON包装到对象中.感谢所有的投票!

I have updated the code for Swift 3 and also showed how to wrap the parsed JSON into objects. Thanks for all the up votes!

import Foundation

struct Weather {
    let id: Int
    let main: String
    let description: String
    let icon: String
}

extension Weather {
    init?(json: [String: Any]) {
        guard
            let id = json["id"] as? Int,
            let main = json["main"] as? String,
            let description = json["description"] as? String,
            let icon = json["icon"] as? String
        else { return nil }
        self.id = id
        self.main = main
        self.description = description
        self.icon = icon
    }
}

var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"

enum JSONParseError: Error {
    case notADictionary
    case missingWeatherObjects
}

var data = jsonStr.data(using: String.Encoding.ascii, allowLossyConversion: false)
do {
    var json = try JSONSerialization.jsonObject(with: data!, options: [])
    guard let dict = json as? [String: Any] else { throw JSONParseError.notADictionary }
    guard let weatherJSON = dict["weather"] as? [[String: Any]] else { throw JSONParseError.missingWeatherObjects }
    let weather = weatherJSON.flatMap(Weather.init)
    print(weather)
}
catch {
    print(error)
}

-上一个答案-

import Foundation

var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)

if let dict = json as? [String: AnyObject] {
    if let weather = dict["weather"] as? [AnyObject] {
        for dict2 in weather {
            let id = dict2["id"]
            let main = dict2["main"]
            let description = dict2["description"]
            println(id)
            println(main)
            println(description)
        }
    }
}

由于我仍在为这个答案投票,我想我会在Swift 2.0上重新访问它:

Since I'm still getting up-votes for this answer, I figured I would revisit it for Swift 2.0:

import Foundation

var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
    var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)

    if let dict = json as? [String: AnyObject] {
        if let weather = dict["weather"] as? [AnyObject] {
            for dict2 in weather {
                let id = dict2["id"] as? Int
                let main = dict2["main"] as? String
                let description = dict2["description"] as? String
                print(id)
                print(main)
                print(description)
            }
        }
    }

}
catch {
    print(error)
}

最大的区别是变量json不再是可选类型,并且不再是do/try/catch语法.我还继续输入了idmaindescription.

The biggest difference is that the variable json is no longer an optional type and the do/try/catch syntax. I also went ahead and typed id, main, and description.

这篇关于在Swift中解析JSON,AnyObject类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆