在Swift 3中解析JSON

21

有人能够找到在Swift 3中解析JSON文件的方法吗?我已经能够获取数据,但是当需要将数据分解成特定字段时就不成功了。我想贴出示例代码,但是我已经试过很多不同的方法并且没有保存任何代码。我想要解析的基本格式类似于这样。谢谢。

{
  "Language": {

    "Field":[
          {
          "Number":"976",
          "Name":"Test"
          },
          {
          "Number":"977",
          "Name":"Test"
          }
       ]
   }
}

您的示例无效JSON。它需要以另一个{...}开头和结尾。 - Jeffery Thomas
我已经修复了。然而,它只是被错误地粘贴在这里。我的实际文件有正确的格式。谢谢。 - SpringN
8个回答

28

你尝试过使用 JSONSerialization.jsonObject(with:options:) 吗?

var jsonString = "{" +
    "\"Language\": {" +
    "\"Field\":[" +
    "{" +
    "\"Number\":\"976\"," +
    "\"Name\":\"Test\"" +
    "}," +
    "{" +
    "\"Number\":\"977\"," +
    "\"Name\":\"Test\"" +
    "}" +
    "]" +
    "}" +
    "}"

var data = jsonString.data(using: .utf8)!

let json = try? JSONSerialization.jsonObject(with: data)

有时候,Swift会产生一些非常奇怪的语法。

if let number = json?["Language"]??["Field"]??[0]?["Number"] as? String {
    print(number)
}

JSON对象层次结构中的所有内容最终都被包装为可选项(即AnyObject?)。 Array<T>下标返回非可选项T。对于这个被包装在可选项中的JSON,数组下标返回Optional<AnyObject>。然而,Dictionary<K,V>下标返回一个Optional<V>。对于这个JSON,下标返回非常奇怪的Optional<Optional<AnyObject>>(即AnyObject??)。

  • json是一个Optional<AnyObject>
  • json?["Language"]返回一个Optional<Optional<AnyObject>>
  • json?["Language"]??["Field"]返回一个Optional<Optional<AnyObject>>
  • json?["Language"]??["Field"]??[0]返回一个Optional<AnyObject>
  • json?["Language"]??["Field"]??[0]?["Number"]返回一个Optional<Optional<AnyObject>>
  • json?["Language"]??["Field"]??[0]?["Number"] as? String返回一个Optional<String>

Optional<String>然后被if let语法用来生成一个String


最后注意:遍历字段数组的方式如下。

for field in json?["Language"]??["Field"] as? [AnyObject] ?? [] {
    if let number = field["Number"] as? String {
        print(number)
    }
}

Swift 4 更新

Swift 4 让这一切变得更加容易处理。我们将再次从测试数据开始(使用"""可以让此过程更轻松愉悦)。

let data = """
{
  "Language": {

    "Field":[
          {
          "Number":"976",
          "Name":"Test"
          },
          {
          "Number":"977",
          "Name":"Test"
          }
       ]
   }
}
""".data(using: .utf8)!

接下来,我们可以定义与您的JSON中使用的对象相关的类。

struct Object: Decodable {
    let language: Language
    enum CodingKeys: String, CodingKey { case language="Language" }
}

struct Language: Decodable {
    let fields: [Field]
    enum CodingKeys: String, CodingKey { case fields="Field" }
}

struct Field: Decodable {
    let number: String
    let name: String
    enum CodingKeys: String, CodingKey { case number="Number"; case name="Name" }
}
CodingKeys 枚举用于将结构体属性映射到 JSON 对象成员字符串。这种映射是由 Decodable 自动完成的。
现在解析 JSON 很简单。
let object = try! JSONDecoder().decode(Object.self, from: data)

print(object.language.fields[0].name)

for field in object.language.fields {
    print(field.number)
}

我怎样才能只获取像number这样的值?这段代码让我得到了field,但是我搞不清接下来该怎么做。 var data = jsonString.data(using: .utf8)! let json = try? JSONSerialization.jsonObject(with: data) if let language = json?["Language"] { if let field = language?["Field"] { print(field) } } - SpringN
@Nas5296,我更新了我的答案以解释如何访问JSON对象。 - Jeffery Thomas
非常感谢!这是一个非常奇怪的格式(经典的Swift),但正是我所需要的! - SpringN
除了Foundation和Glibc,您需要导入其他内容吗?在Swift 3.0版本(swift-3.0-PREVIEW-2)上,我得到了“error: use of unresolved identifier 'JSONSerialization'” 的错误提示。 - Carlos Macasaet

14

Xcode 8和Swift 3中,id现在作为Any而不是AnyObject导入。

这意味着JSONSerialization.jsonObject(with: data)返回Any。因此,您必须将json data转换为特定类型,如[String:Any]。同样适用于json下面的下一个字段。

var jsonString = "{" +
    "\"Language\": {" +
    "\"Field\":[" +
    "{" +
    "\"Number\":\"976\"," +
    "\"Name\":\"Test1\"" +
    "}," +
    "{" +
    "\"Number\":\"977\"," +
    "\"Name\":\"Test2\"" +
    "}" +
    "]" +
    "}" +
"}"

var data = jsonString.data(using: .utf8)!
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
    let language = parsedData["Language"] as! [String:Any]
    print(language)
    let field = language["Field"] as! [[String:Any]]
    let name = field[0]["Name"]!
    print(name) // ==> Test1
}

在实践中,您可能希望在json中嵌套一些特定的字段。假设它是Field数组中第一个元素的Name字段。您可以使用这样的解包链来安全地访问该字段:

var data = jsonString.data(using: .utf8)!
if let json = try? JSONSerialization.jsonObject(with: data) as? [String:Any],
    let language = json?["Language"] as? [String:Any],
    let field = language["Field"] as? [[String:Any]],
    let name = field[0]["Name"] as? String, field.count > 0 {
    print(name) // ==> Test1
} else {
    print("bad json - do some recovery")
}

您可能还想查看苹果公司的Swift博客 在Swift中使用JSON


工作得很好!谢谢。 - Gilad Brunfman

3
将JSON手动塞到字符串中非常麻烦。为什么不将它放到文件中并从文件中读取呢?
Swift 3:
let bundle = Bundle(for: type(of: self))
    if let theURL = bundle.url(forResource: "response", withExtension: "json") {
        do {
            let data = try Data(contentsOf: theURL)
            if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
                grok(parsedData)
            }
        } catch {
            print(error)
        }
    }

0

使用Decodable协议在Swift 4中解析JSON:

我使用您的JSON对象创建了一个mocky文件:

http://www.mocky.io/v2/5a280c282f0000f92c0635e6

这里是解析JSON的代码:

模型创建:

import UIKit

struct Item : Decodable { 
// Properties must be the same name as specified in JSON , else it will return nil
var Number : String
var Name : String
}

struct Language : Decodable {
 var Field : [Item]
}

struct Result : Decodable {
 var Language : Language
}

如果您不确定 JSON 文件中是否缺少某些内容,可以在模型中使用可选项。

这是解析逻辑:

class ViewController: UIViewController {

let url = "http://www.mocky.io/v2/5a280c282f0000f92c0635e6"

private func parseJSON() {

    guard let url = URL(string: url) else { return }

    let session = URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }
        guard let result = try? JSONDecoder().decode(Result.self, from: data) else { return }
        print("\n\nResult : \(result)")
    }
    session.resume()
}

override func viewDidLoad() {
    super.viewDidLoad()
    parseJSON()
}
}

打印输出:

 Result : Result(Language: JSON_Parsing.Language(Field: [JSON_Parsing.Item(Number: "976", Name: "Test"), JSON_Parsing.Item(Number: "977", Name: "Test")]))

这是Github项目链接,你可以查看。


0

使用 Swift 4 简单地解析 JSON

   let url = URL(string: "http://mobileappdevelop.co/TIPIT/webservice/get_my_groups?user_id=5")
    URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
        guard let data = data, error == nil else { return }

        do {
            let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]

             print(json)

            let posts =  json["Field"] as? [[String: Any]] ?? []
            print(posts)
        } catch let error as NSError {
            print(error)
        }

    }).resume()

}

0
使用SwiftJson库。我认为这是一种非常简单的解析方式。
let count: Int? = json["Field"].array?.count
if let ct = count {            
    for index in 0...ct-1{
        let number = json ["Field"][index]["number"].string
        let name = json ["Field"][index]["name"].string 

....

就像这样。


0
 override func viewDidLoad() {
        super.viewDidLoad()
        let url=URL(string:"http://api.androidhive.info/contacts/")
        do {
            let allContactsData = try Data(contentsOf: url!)
            let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
            if let arrJSON = allContacts["contacts"] {
                for index in 0...arrJSON.count-1 {
                    let aObject = arrJSON[index] as! [String : AnyObject]
                    names.append(aObject["name"] as! String)
                    contacts.append(aObject["email"] as! String)
                }
            }
            print(names)
            print(contacts)
            self.tableView.reloadData()
        }
        catch {
        }
    }

-1
dict = {
    message = "Login successfully.";
    status = 1;
    "user_details" =     (
                {
            dob = "1900-11-18";
            email = "rizwan@gmail.com";
            gender = male;
            name = Rizwan;
            nickname = Shaikh;
            "profile_pic" = "1483434421.jpeg";
            "social_id" = "<null>";
            "user_id" = 2;
        }
    );
}

我们可以在 Swift 3 中解析上述 json,代码如下:
var dict2  = dict as! [String : Any]
print(dict);
let demoStr = dict2["message"] as! String
print(demoStr)
let demoArray = dict2["user_details"] as! [Any]
let demoDict = demoArray[0] as! [String:Any]
print(demoDict["dob"]!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接