JSON Parsing in Swift 3

前端 未结 8 803
暖寄归人
暖寄归人 2020-12-01 11:05

Has anyone been able to find a way to parse through JSON files in Swift 3? I have been able to get the data to return but I am unsuccessful when it comes to breaking the dat

8条回答
  •  执笔经年
    2020-12-01 11:28

    Have you tried 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 sometimes produces some very odd syntax.

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

    Everything in the JSON object hierarchy ends up getting wrapped as an optional (ie. AnyObject?). Array subscript returns a non-optional T. For this JSON, which is wrapped in an optional, array subscript returns Optional. However, Dictionary subscript returns an Optional. For this JSON, subscript returns the very odd looking Optional> (ie. AnyObject??).

    • json is an Optional.
    • json?["Language"] returns an Optional>.
    • json?["Language"]??["Field"] returns an Optional>.
    • json?["Language"]??["Field"]??[0] returns an Optional.
    • json?["Language"]??["Field"]??[0]?["Number"] returns an Optional>.
    • json?["Language"]??["Field"]??[0]?["Number"] as? String returns an Optional.

    The Optional is then used by the if let syntax to product a String.


    Final note: iterating the field array looks like this.

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

    Swift 4 Update

    Swift 4 makes this all much easier to deal with. Again we will start with your test data (""" makes this so much nicer).

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

    Next we can define classes around the objects used in your 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" }
    }
    

    The CodingKeys enum is how struct properties are mapped to JSON object member strings. This mapping is done automagically by Decodable.


    Parsing the JSON now is simple.

    let object = try! JSONDecoder().decode(Object.self, from: data)
    
    print(object.language.fields[0].name)
    
    for field in object.language.fields {
        print(field.number)
    }
    

提交回复
热议问题