0

来自 API 的格式非常糟糕的 json 响应:

[{
   "id": "1",
   "shape": "{
       "coordinates": "[[12.557642081093963,99.95730806607756], [12.558081912207575,99.96078957337888], [12.558469381851197,99.96072520036252], [12.558029551400157,99.9572275998071]]"}"
}]

我需要将这个“形状”键解码到我的自定义结构中,这似乎没什么大不了的,但我有引号包裹着数组"[]"

所以,我有什么:

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    id = try container.decode(Identifier.self, forKey: .id)
    shape = try container
        .nestedContainer(keyedBy: ShapeCoordinatesCodingKeys.self, forKey: .shape)
        .decode([[Double]].self, forKey: .coordinates)
        .flatMap {
            $0.count > 1 ? Location(latitude: $0[0], longitude: $0[1]) : nil
    }
}

合理地有错误

"Expected to decode Array<Any> but found a string/data instead."

而且这个电话有效(仅用于测试目的):

po try container.nestedContainer(keyedBy: ShapeCoordinatesCodingKeys.self, forKey: .shape).decode(String.self, forKey: .coordinates)

并有这个输出:

"[[12.557642081093963,99.95730806607756], [12.558081912207575,99.96078957337888], [12.558469381851197,99.96072520036252], [12.558029551400157,99.9572275998071]]"

所以有什么方法可以将这个字符串样式包装的 json 数组解码为 Swift 数组Codable

我设法做了一些解决方法,它有效,但它似乎根本不是一个好的解决方案。将在此处发布,但问题“是否有任何方法可以正常使用 Codable 实现此功能”仍处于打开状态

public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Identifier.self, forKey: .id)

        do {
            shape = try container
                .nestedContainer(keyedBy: ShapeCoordinatesCodingKeys.self, forKey: .shape)
                .decode([[Double]].self, forKey: .coordinates)
                .flatMap {
                    $0.count > 1 ? Location(latitude: $0[0], longitude: $0[1]) : nil
            }
        }
        catch {

            guard let coordinatesData = try container
                .nestedContainer(keyedBy: ShapeCoordinatesCodingKeys.self, forKey: .shape)
                .decode(String.self, forKey: .coordinates).data(using: .utf8) else {
                    throw DecodingError.dataCorrupted(
                        DecodingError.Context(
                            codingPath: [ShapeCoordinatesCodingKeys.coordinates],
                            debugDescription: "Array or String?"
                        )
                    )
            }

            shape = try JSONDecoder()
                .decode([[Double]].self, from: coordinatesData)
                .flatMap {
                $0.count > 1 ? Location(latitude: $0[0], longitude: $0[1]) : nil
            }
        }
    }
4

1 回答 1

0

这可能会让您了解如何处理此类问题String

let rawString: String = "[[12.557642081093963,99.95730806607756], [12.558081912207575,99.96078957337888], [12.558469381851197,99.96072520036252], [12.558029551400157,99.9572275998071]]"

基本上这里发生的事情是将其转换StringData并尝试通过 data将其解码为 JSON 来将其解析为[[Double]]

if let data: Data = rawString.data(using: .utf8) {
    let coordinates: [[Double]]? = try? JSONDecoder().decode([[Double]].self, from: data)
    // yes, it is an array now as I wanted!
}

注意:只要String应该是引号内的有效 JSON,就不会失败。当然,为什么响应仅间接包含 JSON 是非常可疑的,但是如果您(正如我在上面所说的)期望那里有一个有效的 JSON,那么您可以轻松地桥接这种情况。

于 2017-12-27T09:13:01.810 回答