【问题标题】:JSON Parsing in Swift 3Swift 3 中的 JSON 解析
【发布时间】:2016-07-02 00:42:06
【问题描述】:

有没有人能够找到在 Swift 3 中解析 JSON 文件的方法?我已经能够让数据返回,但是在将数据分解为特定字段时我没有成功。我会发布示例代码,但我经历了很多不同的方法都没有成功,并且没有保存任何方法。我要解析的基本格式是这样的。提前致谢。

{
  "Language": {

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

【问题讨论】:

  • 您的样本是无效的 JSON。它需要以另一个{…} 开头和结尾。
  • 我解决了这个问题。但是,它只是在这里错误地粘贴了。我的实际文件格式正确。谢谢

标签: json xcode swift parsing


【解决方案1】:

你试过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??)。

  • jsonOptional<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>

然后if let 语法使用Optional<String> 生成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)
}

【讨论】:

  • 我怎样才能开始只提取数字之类的值?这段代码让我进入现场,但我不知道接下来会发生什么。 var data = jsonString.data(使用:.utf8)!让 json = 试试? JSONSerialization.jsonObject(with: data) if let language = json?["Language"] { if let field = language?["Field"] { print(field) } }
  • @Nas5296 我更新了关于如何访问 JSON 对象的答案。
  • 非常感谢!这是一种非常奇怪的格式(经典 Swift),但正是我需要的!
  • 除了 Foundation 和 Glibc 之外,你还需要导入什么吗?我得到:error: use of unresolved identifier 'JSONSerialization' 在 Swift 版本 3.0 (swift-3.0-PREVIEW-2) 上。
【解决方案2】:

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")
}

您还可以查看 Apple 的 Swift 博客 Working with JSON in Swift

【讨论】:

  • 效果很好!谢谢
【解决方案3】:

手动将 JSON 推入字符串是一种皮塔饼。为什么不直接将 JSON 放入一个文件并读入呢?

斯威夫特 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)
        }
    }

【讨论】:

    【解决方案4】:
     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 {
            }
        }
    

    【讨论】:

      【解决方案5】:

      使用可解码协议在 swift 4 中解析 JSON:

      我使用您的 json 对象创建了一个模拟文件:

      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 文件中可能缺少某些内容,您可以在模型中使用 optional。

      这是解析逻辑:

      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")]))
      

      This the github Project link. You can check.

      【讨论】:

        【解决方案6】:

        以简单的方式使用 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()
        
        }
        

        【讨论】:

          【解决方案7】:

          使用 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 
          

          ....

          像这样。

          【讨论】:

            【解决方案8】:
            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"]!)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多