6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftのCodableでCustomな型(ObjectじゃなくてPrimitiveなValue)を扱う方法

Last updated at Posted at 2019-03-13

JSONのObjectに当たるもののclass(struct)を定義するのはわかるのだが、JSONのprimitiveValue(numberとかstringとか)に当たるもののclass(struct)を定義する方法が全然ドキュメントされていないのでメモ。

まとめ

  • CustomPrimitiveValueのCodable実装でinit(from decoder)とencode(to)を自分で実装しよう
  • singlevaluecontainerを使おう

フルサンプル

PersonがObject.
NameがPrimitiveValue(string互換).

構造
person: {
  name: Name
}

です。以下どうぞ

Name.swift

// こいつはjson上Objectではなくstringと同様のprimitiveなvalueとして扱いたい
struct Name {
    let string: String
    
    init(_ string: String) {
        self.string = string
    }
}

extension Name: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        self.string = try container.decode(String.self)
    }
}

extension Name: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(string)
    }
}
Person.swift
struct Person {
    let name: Name? // ←独自の型且つOptionalだと自動的に動かない 独自の型がCodableである必要がある。 今回はNameをCodableにしたので自動的に動く
}

extension Person: Codable {
    enum CodingKeys: String, CodingKey {
        case name
    }
}
Test.swift
func testEncode() -> String {
    let person = Person(name: Name("taro"))
    let data = try! JSONEncoder().encode(person)
    return String(data: data, encoding: .utf8)!
}
testEncode() // => "{"name":"taro"}"


extension Person: CustomStringConvertible {
    var description: String {
        return "Person<name: \(name?.description ?? "nil")>"
    }
}

extension Name: CustomStringConvertible {
    var description: String {
        return "Name<\(string.description)>"
    }
}

func testDecode() -> Person {
    let json = "{\"name\":\"suzuki12\"}"
    let data = json.data(using: .utf8)!
    return try! JSONDecoder().decode(Person.self, from: data)
}
testDecode() // => Person<name: Name<suzuki>>

蛇足

公式ドキュメント(Apple)でSingleValueContainerが触れられてないのどういうこと。流し読みしたら、primitiveな値にCodable使うべきではないのかなと勘違いするところだった。

独自のEncoderを作る方法はこちらがとてもわかりやすいです
https://stackoverflow.com/questions/45169254/swift-custom-encoder-decoder-to-strings-resource-format

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?