Last active
June 27, 2020 06:39
-
-
Save hlung/601d38bfe19788a57b4bcb36ada23c6d to your computer and use it in GitHub Desktop.
Decodes multiple layers of nested containers using a String array for key path. (It's actually cleaner to declare another struct for the nested data. But this is to show how this can be done.)
This file contains hidden or 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 | |
// Allows defining CodingKey from String | |
struct DynamicCodingKey: CodingKey { | |
var intValue: Int? | |
var stringValue: String | |
init?(intValue: Int) { | |
assertionFailure("Not implemented") | |
return nil | |
} | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
} | |
} | |
extension KeyedDecodingContainer where Key == DynamicCodingKey { | |
// Decodes multiple layers of nested containers using a String array for key path. | |
func decode<T: Decodable>(_ type: T.Type, forKeyPath keys: [String]) throws -> T? { | |
var container: KeyedDecodingContainer = self | |
for key in keys { | |
guard let realKey = container.allKeys.first(where: { $0.stringValue == key }) else { return nil } | |
if key == keys.last { | |
return try container.decode(T.self, forKey: realKey) | |
} | |
else { | |
container = try container.nestedContainer(keyedBy: Key.self, forKey: realKey) | |
} | |
} | |
return nil | |
} | |
} |
This file contains hidden or 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 | |
@testable import Viki | |
import XCTest | |
class DynamicCodingKeyTests: XCTestCase { | |
private struct Foo: Decodable { | |
let teamName: String? | |
init(from decoder: Decoder) throws { | |
let container = try decoder.container(keyedBy: DynamicCodingKey.self) | |
self.teamName = try container.decode(String.self, forKeyPath: ["team", "name"]) | |
} | |
} | |
func testDefaultSettingsFileNotFound() throws { | |
let data = """ | |
{ | |
"team": { "name": "foo" } | |
} | |
""".data(using: .utf8)! | |
let output = try JSONDecoder().decode(Foo.self, from: data) | |
XCTAssertEqual(output.teamName, "foo") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment