Skip to content

Instantly share code, notes, and snippets.

@takasek
Last active October 3, 2018 18:30
Show Gist options
  • Save takasek/ffa9c35a7c1f0baf0f9ee037937fcc24 to your computer and use it in GitHub Desktop.
Save takasek/ffa9c35a7c1f0baf0f9ee037937fcc24 to your computer and use it in GitHub Desktop.
Decoder, DecodingContainerの、デコード先の型を推論させたい!明示的に指定したくない! ref: http://qiita.com/takasek/items/f51c26a8ee6a2929bb6e
import Foundation
extension JSONDecoder {
func decode<T: Decodable>(from data: Data) throws -> T {
return try decode(T.self, from: data)
}
}
extension PropertyListDecoder {
func decode<T: Decodable>(from data: Data) throws -> T {
return try decode(T.self, from: data)
}
}
extension KeyedDecodingContainerProtocol {
func decode(forKey key: Self.Key) throws -> Bool { return try decode(Bool.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Int { return try decode(Int.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Int8 { return try decode(Int8.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Int16 { return try decode(Int16.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Int32 { return try decode(Int32.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Int64 { return try decode(Int64.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> UInt { return try decode(UInt.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> UInt8 { return try decode(UInt8.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> UInt16 { return try decode(UInt16.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> UInt32 { return try decode(UInt32.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> UInt64 { return try decode(UInt64.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Float { return try decode(Float.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> Double { return try decode(Double.self, forKey: key) }
func decode(forKey key: Self.Key) throws -> String { return try decode(String.self, forKey: key) }
func decode<T: Decodable>(forKey key: Self.Key) throws -> T { return try decode(T.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Bool? { return try decodeIfPresent(Bool.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Int? { return try decodeIfPresent(Int.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Int8? { return try decodeIfPresent(Int8.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Int16? { return try decodeIfPresent(Int16.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Int32? { return try decodeIfPresent(Int32.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Int64? { return try decodeIfPresent(Int64.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> UInt? { return try decodeIfPresent(UInt.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> UInt8? { return try decodeIfPresent(UInt8.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> UInt16? { return try decodeIfPresent(UInt16.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> UInt32? { return try decodeIfPresent(UInt32.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> UInt64? { return try decodeIfPresent(UInt64.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Float? { return try decodeIfPresent(Float.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> Double? { return try decodeIfPresent(Double.self, forKey: key) }
func decodeIfPresent(forKey key: Self.Key) throws -> String? { return try decodeIfPresent(String.self, forKey: key) }
func decodeIfPresent<T: Decodable>(forKey key: Self.Key) throws -> T? { return try decodeIfPresent(T.self, forKey: key) }
}
extension UnkeyedDecodingContainer {
mutating func decode() throws -> Bool { return try decode(Bool.self) }
mutating func decode() throws -> Int { return try decode(Int.self) }
mutating func decode() throws -> Int8 { return try decode(Int8.self) }
mutating func decode() throws -> Int16 { return try decode(Int16.self) }
mutating func decode() throws -> Int32 { return try decode(Int32.self) }
mutating func decode() throws -> Int64 { return try decode(Int64.self) }
mutating func decode() throws -> UInt { return try decode(UInt.self) }
mutating func decode() throws -> UInt8 { return try decode(UInt8.self) }
mutating func decode() throws -> UInt16 { return try decode(UInt16.self) }
mutating func decode() throws -> UInt32 { return try decode(UInt32.self) }
mutating func decode() throws -> UInt64 { return try decode(UInt64.self) }
mutating func decode() throws -> Float { return try decode(Float.self) }
mutating func decode() throws -> Double { return try decode(Double.self) }
mutating func decode() throws -> String { return try decode(String.self) }
mutating func decode<T: Decodable>() throws -> T { return try decode(T.self) }
mutating func decodeIfPresent() throws -> Bool? { return try decodeIfPresent(Bool.self) }
mutating func decodeIfPresent() throws -> Int? { return try decodeIfPresent(Int.self) }
mutating func decodeIfPresent() throws -> Int8? { return try decodeIfPresent(Int8.self) }
mutating func decodeIfPresent() throws -> Int16? { return try decodeIfPresent(Int16.self) }
mutating func decodeIfPresent() throws -> Int32? { return try decodeIfPresent(Int32.self) }
mutating func decodeIfPresent() throws -> Int64? { return try decodeIfPresent(Int64.self) }
mutating func decodeIfPresent() throws -> UInt? { return try decodeIfPresent(UInt.self) }
mutating func decodeIfPresent() throws -> UInt8? { return try decodeIfPresent(UInt8.self) }
mutating func decodeIfPresent() throws -> UInt16? { return try decodeIfPresent(UInt16.self) }
mutating func decodeIfPresent() throws -> UInt32? { return try decodeIfPresent(UInt32.self) }
mutating func decodeIfPresent() throws -> UInt64? { return try decodeIfPresent(UInt64.self) }
mutating func decodeIfPresent() throws -> Float? { return try decodeIfPresent(Float.self) }
mutating func decodeIfPresent() throws -> Double? { return try decodeIfPresent(Double.self) }
mutating func decodeIfPresent() throws -> String? { return try decodeIfPresent(String.self) }
mutating func decodeIfPresent<T: Decodable>() throws -> T? { return try decodeIfPresent(T.self) }
}
extension SingleValueDecodingContainer {
func decode() throws -> Bool { return try decode(Bool.self) }
func decode() throws -> Int { return try decode(Int.self) }
func decode() throws -> Int8 { return try decode(Int8.self) }
func decode() throws -> Int16 { return try decode(Int16.self) }
func decode() throws -> Int32 { return try decode(Int32.self) }
func decode() throws -> Int64 { return try decode(Int64.self) }
func decode() throws -> UInt { return try decode(UInt.self) }
func decode() throws -> UInt8 { return try decode(UInt8.self) }
func decode() throws -> UInt16 { return try decode(UInt16.self) }
func decode() throws -> UInt32 { return try decode(UInt32.self) }
func decode() throws -> UInt64 { return try decode(UInt64.self) }
func decode() throws -> Float { return try decode(Float.self) }
func decode() throws -> Double { return try decode(Double.self) }
func decode() throws -> String { return try decode(String.self) }
func decode<T: Decodable>() throws -> T { return try decode(T.self) }
}
struct Hoge: Decodable {
let id: Int
let text: String
let url: URL
let option: String?
private enum CodingKeys: CodingKey {
case id
case text
case url
case option
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// 普通は型を指定しなければいけないけど、
// id = try container.decode(Int.self, forKey: .id)
// text = try container.decode(String.self, forKey: .text)
// url = try container.decode(URL.self, forKey: .url)
// option = try container.decodeIfPresent(String.self, forKey: .option)
// 理屈としては、型を省略しても推論可能なので、extensionを通して実現
id = try container.decode(forKey: .id)
text = try container.decode(forKey: .text)
url = try container.decode(forKey: .url)
option = try container.decodeIfPresent(forKey: .option)
}
}
let data = """
{
"id": 100,
"text": "text",
"url": "https://www.yahoo.co.jp",
"option": null,
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
//let h: Hoge = try! decoder.decode(Hoge.self, from: data) // 普通は引数として型を指定しなきゃいけないけど、
let h: Hoge = try! decoder.decode(from: data) // 理屈としては型を省略しても推論可能なので、extensionを通して実現
print(h)
// Hoge(id: 100, text: "text", url: https://www.yahoo.co.jp, option: nil)
@av0c0der
Copy link

av0c0der commented Oct 3, 2018

I can't get the difference between what you have here and the following extension from this post:

import Foundation

extension KeyedDecodingContainerProtocol {

  func decode<T: Decodable>(forKey key: Key) throws -> T {
    return try decode(T.self, forKey: key)
  }

  func decode<T: Decodable>(forKey key: Key, default defaultExpression: @autoclosure () -> T) throws -> T {
    return try decodeIfPresent(T.self, forKey: key) ?? defaultExpression()
  }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment