Можете ли вы декодировать дочерний объект JSON в его строковое представление вместо конкретного типа? - PullRequest
1 голос
/ 23 января 2020

Хорошо, задаю вопрос, похожий на этот , который я опубликовал на днях. Разница здесь в том, что мне интересно, может ли json подобъекта считываться как экранированная строка самого JSON, а не быть декодированным.

Учитывайте это json ...

{
    "value" : "SomeValue",
    "child" : {
        "prop1" : "Value1",
        "prop2" : "Value2"
    }
}

Вы можете без проблем декодировать это в эти классы ...

class Wrapper : Codable {
    let value : String
    let child : ChildObject
}

class ChildObject : Codable {
    let prop1 : String
    let prop2 : String
}

Что мне интересно, так это возможность написать собственный декодер, который позволит мне декодировать его в этот класс. ...

class Wrapper : Codable {
    let value : String
    let child : String  <-- Note: String
}

... и Wrapper.child равен этому ...

// Wrapper.child holds a string containing the escaped, raw JSON
Wrapper.child == "{\"prop1\":\"Value1\",\"prop2\":\"Value2\"}"

Единственное решение, которое я нашел до сих пор, - это явное декодирование во что-то вроде AnyCodable (на GitHub здесь ), которая является прославленной реализацией с анонимной кодировкой, затем повторно сериализовайте ее обратно в JSON, прежде чем назначить ее фактическому свойству в инициализаторе. Кажется, немного излишним, но это работает.

public init(from decoder: Decoder) throws {

    // Get the container for the CodingKeys
    let container = try decoder.container(keyedBy: CodingKeys.self)

    // Set 'value' directly as a string
    value = try container.decode(String.self, forKey: .value)

    // For 'child', Decode to an anonymous codable type,
    // Re-serialize that codable type back to JSON data
    // Convert that JSON data into a string, using that to set 'child'

    // decode an type-erased Codable object
    let anyCodable = try container.decode(AnyCodable.self, forKey: .child)

    // Reencode it back to JSON
    let encoder = JSONEncoder()
    let childJsonData = try encoder.encode(anyCodable)

    // Set that JSON on the object's string property
    child = String(data:childJsonData, encoding:.utf8)!
}

Мне просто воняет, когда я декодирую, просто снова перекодирую. Надеюсь, что есть способ сделать это без этого дополнительного шага.

1 Ответ

0 голосов
/ 23 января 2020

Вы ищете альтернативные решения, и ниже приведено альтернативное.

Реализация CustomStringConvertible для типа ChildObject.

class ChildObject : Codable, CustomStringConvertible {
    let prop1 : String
    let prop2 : String

    var description: String {
        return "\(prop1) --- \(prop2)"
    }
}

и затем вызов описание геттер

child = childJsonData.description
...