すでにエンコードされたJSONフラグメントであるcontents
の値を含む、次のようなデータ構造を想像してください。
let partial = """
{ "foo": "Foo", "bar": 1 }
"""
struct Document {
let contents: String
let other: [String: Int]
}
let doc = Document(contents: partial, other: ["foo": 1])
結合されたデータ構造は、contents
をそのまま使用し、other
をエンコードする必要があります。
{
"contents": { "foo": "Foo", "bar": 1 },
"other": { "foo": 1 }
}
Encodable
の使用次のEncodable
の実装はDocument
をJSONとしてエンコードしますが、contents
も文字列に再エンコードします。つまり、引用符で囲まれ、すべての"
引用符は\"
にエスケープされました。
extension Document : Encodable {
enum CodingKeys : String, CodingKey {
case contents
case other
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(contents, forKey: .contents)
try container.encode(other, forKey: .other)
}
}
{
"contents": "{\"foo\": \"Foo\", \"bar\": 1}",
"other": { "foo": 1 }
}
encode
をそのままcontents
を通過させるにはどうすればよいですか?
あなたはこれを行うことでそれを達成することができます:
let partial = """
{
"foo": "Foo",
"bar": 1
}
"""
// declare a new type for `content` to deal with it as an object instead of a string
struct Document {
let contents: Contents
let other: [String: Int]
struct Contents: Codable {
let foo: String
let bar: Int
}
}
extension Document : Encodable {
enum CodingKeys: String, CodingKey {
case contents
case other
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(contents, forKey: .contents)
try container.encode(other, forKey: .other)
}
}
let decoder = JSONDecoder()
let contents = try decoder.decode(Document.Contents.self, from: partial.data(using: .utf8)!)
let encoder = JSONEncoder()
let doc = Document(contents: contents, other: ["foo": 1])
let result = try encoder.encode(doc)
print(String(data: result, encoding: .utf8)!)
基本的に、最初にpartial
をデコードして処理し、次にそのデコード結果をDocument
に渡すことができます。
出力は次のようになります。
{"other":{"foo":1}、 "contents":{"foo": "Foo"、 "bar":1}}