1

我知道其他问题已经涵盖了这一点,但我已经关注了它们,但我仍然感到困惑。这是我的 JSON 结构:

      {
       "FindBoatResult": {
       "num_boats": 10,
       "boat": [
         {
           "num_segments": 1,
           "segments": [
              {
               "ident": "String",
                "origin" : {
                         "code" : "String"
                 },
           },
         ]
        }

等等......但这与结构一样深。每个 JSON 响应中有多个“段”返回。在 Swift 我有这个代码。

struct Result : Decodable {
    let FindBoatResult : FindBoatResult
}
struct FindBoatResult : Decodable {
    let boats : Boats
    let num_boats : Int
}
struct Boats : Decodable {
    let segments : [Segments]
}
struct Segments : Decodable {
    let ident : String?
    let origin : Origin
}
struct Origin : Decodable {
    let code : String
}

func getBoats() {

let urlString = "http://myApi"
guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else {return}
        let dataAsString = String(data: data, encoding: .utf8)
        //print(dataAsString)

        do {
            let boats = try
                JSONDecoder().decode(FindBoatResult.self, from: data)

            print(boats)
        } catch {
            print(err) 
        }  
    }.resume()
}

这失败并抛出错误,但错误打印为 nil ..所以我不知道我错过了什么。dataAsString 按预期打印出 JSON,所以我知道“数据”很好。

4

2 回答 2

1

扩展 Paulo 的答案,我可能会进一步建议,如果您坚持使用具有不符合 Swift 属性名称约定的键的 JSON,则使用该CodingKeys模式将 JSON 键转换为更好的 Swift 属性名称,例如:

struct BoatResult: Decodable {           // I'd simplify this name
    let boatCollection: BoatCollection

    enum CodingKeys: String, CodingKey {
        case boatCollection = "FindBoatResult"
    }
}

struct BoatCollection: Decodable {       // I'd simplify this, too, removing "Find" from the name; verbs are for methods, not properties 
    let boats: [Boat]
    let numberOfBoats: Int

    enum CodingKeys: String, CodingKey {
        case boats = "boat"              // "boat" isn't great property name for an array of boats, so let's map the poor JSON key to better Swift name here
        case numberOfBoats = "num_boats" // likewise, let's map the "_" name with better camelCase property name
    }
}

struct Boat: Decodable {                 // This entity represents a single boat, so let's use "Boat", not "Boats"
    let segments: [Segment]
}

struct Segment: Decodable {              // This entity represents a single segment, so let's use "Segment", not "Segments"
    let identifier: String
    let origin: Origin

    enum CodingKeys: String, CodingKey {
        case identifier = "ident"        // `ident` isn't a common name for identifier, so let's use something more logical
        case origin
    }
}

struct Origin: Decodable {
    let code: String
}

因此,例如,boats在表示对象数组时使用复数形式(例如 ),并将CodingKeys误导性boatJSON 键映射到这个命名更好的boats数组引用。或者当你有一个类似的键时num_boats,不要觉得你必须在你的 Swift 属性中使用那个坏名字并使用更好的东西numberOfBoatscount或其他),并且失去_非常不Swifty的语法。

显然,如果您控制 JSON 的设计,您可以在那里修复其中一些选择不当的键名,但即使您决定希望您的 Web 服务使用该_语法,请继续使用CodingKeys以确保你的 Swift 对象遵守 camelCase 约定。

于 2017-10-27T06:58:45.150 回答
1

我发现了几个小问题。尝试替换这个:

struct FindBoatResult: Decodable {
    let boats: Boats
    let num_boats: Int
}
struct Boats: Decodable {
    let segments: [Segments]
}

和:

struct FindBoatResult: Decodable {
    let boat: [Boat]
    let num_boats: Int
}
struct Boat: Decodable {
    let segments: [Segments]
}

Result最后,使用类型 (not )进行解码FindBoatResult

JSONDecoder().decode(Result.self, from: data)
于 2017-10-27T00:40:17.567 回答