SingleValueEncodingContainerとKeyedEncodingContainerでEncodableを型に持つ変数をエンコードする時の挙動の違いについて(KeyedEncodingContainerだとエラーが出る)
swift初心者です。
let foo: Encodable
などのEncodable
の型を持つ変数をJSONEncoder
でエンコードしたいです。
調べたところ、https://forums.swift.org/t/how-to-encode-objects-of-unknown-type/12253
のサイトより、
import Foundation
extension Encodable {
fileprivate func encode(to container: inout SingleValueEncodingContainer) throws {
try container.encode(self)
}
}
struct AnyEncodable1 : Encodable {
var value: Encodable
init(_ value: Encodable) {
self.value = value
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try value.encode(to: &container)
}
}
struct MyThing : Encodable {
let myURL = AnyEncodable1(URL(string: "http://swift.org")!)
}
let url = URL(string: "http://swift.org")
let encoder = JSONEncoder()
var data = try encoder.encode(MyThing())
とするとEncodable
の変数もエンコードできることがわかりました。
しかし、このコードだとEncodable
をAnyEncodable
1つにつき1個しか保存できません。
そこで、
extension Encodable {
fileprivate func encode<K>(to container: inout KeyedEncodingContainer<K>, for key: CodingKey {
try container.encode(self, forKey: key)
// error: Cannot invoke 'encode' with an argument list of type '(Self, forKey: CodingKey)'
}
}
struct AnyEncodable1 : Encodable {
var value: Encodable
init(_ value: Encodable) {
self.value = value
}
enum CodingKeys: String, CodingKey {
case value
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try value.encode(to: &container, for: .value)
}
}
struct MyThing : Encodable {
let myURL = AnyEncodable1(URL(string: "http://swift.org")!)
}
let url = URL(string: "http://swift.org")
let encoder = JSONEncoder()
var data = try encoder.encode(MyThing())
というようにSingleValueEncodingContainer
をKeyedEncodingContainer
に入れ替えました。しかし、入れ替えると先程までは出ていなかったエラーが出ました。
SingleValueEncodingContainer
とKeyedEncodingContainer
のencodeメソッドの宣言はそれぞれ
// SingleValueEncodingContainer
mutating func encode<T>(_ value: T) throws where T : Encodable
// KeyedEncodingContainer
mutating func encode<T>(_ value: T, forKey key: KeyedEncodingContainer.Key) throws where T : Encodable
とKeyedEncodingContainer
にはキーが必要だということ以外は変わりません。
しかし、なぜKeyedEncodingContainer
ではエラーが出るのでしょうか。
ちなみにUnkeyedEncodingContainer
に入れ替えるとエラーは出ませんでした。
なぜこのようになるか理由を教えていただけると幸いです。
よろしくお願い致します。
swift4、xcode9.2です。