Last active
October 28, 2019 22:35
-
-
Save GeekAndDad/c3b3fb030595b18fe153d526a815128e to your computer and use it in GitHub Desktop.
How to make an AnyEncodable protocol that allows you to pass any struct conforming to Encodable to a function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// based on clever example from Nick Lockwood: https://gist.github.com/nicklockwood/833fabacbc4b2d11ae7c7d4752b8fd18 | |
// I only needed Encodable so trimmed it down to just that. | |
protocol AnyEncodableValue: Encodable {} | |
extension AnyEncodableValue { | |
func encode(to container: inout SingleValueEncodingContainer) throws { | |
try container.encode(self) | |
} | |
} | |
struct AnyEncodable: Encodable { | |
let value: AnyEncodableValue | |
init(_ value: AnyEncodableValue) { | |
self.value = value | |
} | |
func encode(to encoder: Encoder) throws { | |
var container = encoder.singleValueContainer() | |
try value.encode(to: &container) | |
} | |
} | |
// Test it out: | |
struct Bar: AnyEncodableValue { | |
var bar: Int | |
} | |
struct Baz: AnyEncodableValue { | |
var baz: String | |
} | |
let coder = JSONEncoder() | |
coder.outputFormatting = .prettyPrinted | |
let values: [AnyEncodableValue] = [ | |
Bar(bar: 5), | |
Baz(baz: "Hello"), | |
] | |
let typeErasedValues = values.map(AnyEncodable.init) | |
let data = try coder.encode(typeErasedValues) | |
print(String(data: data, encoding: .utf8)!) | |
// try as function argument: | |
func test(value: [AnyEncodable]) throws -> Data { | |
let coder = JSONEncoder() | |
coder.outputFormatting = .prettyPrinted | |
let data = try coder.encode(value) | |
return data | |
} | |
let dd = try test(value: typeErasedValues) | |
print(String(data: dd, encoding: .utf8)!) | |
// try single value | |
let typeErasedValue = AnyEncodable(values[0]) | |
func test(value: AnyEncodable) throws -> Data { | |
let coder = JSONEncoder() | |
coder.outputFormatting = .prettyPrinted | |
let data = try coder.encode(value) | |
return data | |
} | |
let d = try test(value: typeErasedValue) | |
print(String(data: d, encoding: .utf8)!) | |
// Single value without the pre-type erasing step required (nice!): | |
func test(value: AnyEncodableValue) throws -> Data { | |
let typeErasedValue = AnyEncodable(value) | |
let coder = JSONEncoder() | |
coder.outputFormatting = .prettyPrinted | |
let data = try coder.encode(typeErasedValue) | |
return data | |
} | |
let d3 = try test(value: values[0]) | |
print(String(data: d3, encoding: .utf8)!) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Oi! Thanks so much for the reply! Made me look again and realize my test code was flawed (grrr). Sure enough! As you said, it works great:
produces:
Bingo! 💥