【问题标题】:Swift 4 Codable decode array wrapped with qoutes用引号包裹的 Swift 4 Codable 解码数组
【发布时间】:2017-12-27 08:28:05
【问题描述】:

来自 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]]"

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

我设法做了一些解决方法,它有效,但它似乎根本不是一个好的解决方案。将在此处发布,但“是否有任何方法可以正常使用 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
            }
        }
    }

【问题讨论】:

  • 因为coordinates 的值似乎是纯String 而不是Array,您需要将该特定的String 值转换为JSON(如果它应该是一个有效的 JSON)并单独对其进行解码。
  • @holex 这个是合法的json,但是因为被当作String处理所以不能正常解码,这里不能怪JSONDecoder,这都可以理解
  • 这似乎是故意发送为String 而不是Array(出于某种原因),这纯粹是后端的情况,即使该字符串当前格式为一个有效的 JSON,从解析器的角度来看,它仍然是一个原始字符串,并且它可以在任何时候进行任何其他操作 - 显然 JSONEcoder 无法将其解析为原始字符串的值,而不是可解码的结构。

标签: json swift swift4 codable decodable


【解决方案1】:

这可能会让你知道如何处理这样的String

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

基本上这里发生的是将String 转换回Data 并尝试通过将其解码为[[Double]] 来将这个 data 解析为JSON:

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,那么您可以轻松地桥接这种情况。

【讨论】:

  • 它对我有用,我在这篇文章之后就想到了这一点,但这似乎不是一个好的解决方案,但作为一种解决方法,它确实有效。谢谢
  • 如果后端 API 以良好的可解析结构发送数据,则“好”的解决方案 - 但这可能不是您可以影响的。
  • 嗨,Holex。我希望你一切都好。请不要回滚我的大小写(和拼写)修复 - 它们是合法的更改。我们在这里偏爱技术写作。谢谢!
  • 感谢您的回复,我很欣赏清晰的观点陈述。我的案例编辑确实增加了一些东西——它们增加了可读性和标准英语写作规则的应用。我会尝试获得版主的意见,然后也许我可以在聊天中回复您?如果可以的话,我很想反对这种内容损害,我希望我能在我这样做的时候让你站在一边。我的编辑完全出于质量原因。
  • 所以,当你认为人们赞成你在手机上发帖时,我不怀疑你是认真的,但我认为这是错误的,原因我已经列出了。既然我们还是在这里聊天,我很想知道你为什么这样做——如果你愿意,请解释一下。你的个人资料很好,即使在我看来,这是故意错误的——但你的个人资料是你的事。答案中的材料是共同的责任,不做改进应被视为故意破坏。我会告诉你我可以从版主那里得到什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-04
相关资源
最近更新 更多