Created
May 17, 2018 16:14
-
-
Save aunnnn/9a6b4608ae49fe1594dbcabd9e607834 to your computer and use it in GitHub Desktop.
Decodable from nested keys
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
{ | |
"applmusic": { | |
"code": "AAPL", | |
"quality": "good", | |
"line": "She told me don't worry" | |
}, | |
"spotify": { | |
"differentcode": "SPOT", | |
"music_quality": "good", | |
"spotify_specific_code": "absent in apple" | |
}, | |
"amazon": { | |
"amzncode": "SPOT", | |
"music_quality": "good", | |
"stanley": "absent in apple" | |
}, | |
"nest1": { | |
"nest2": { | |
"amzncode": "Nest work", | |
"music_quality": "Great", | |
"stanley": "Oh yes", | |
"nest3": { | |
"amzncode": "Nest work again!!!", | |
"music_quality": "Great", | |
"stanley": "Oh yes" | |
} | |
}, | |
"name": "aunnnn" | |
} | |
} |
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 UIKit | |
struct Applmusic: Decodable { | |
let code: String | |
let quality: String | |
let line: String | |
} | |
struct Spotify: Decodable { | |
let differentcode: String | |
let music_quality: String | |
let spotify_specific_code: String | |
} | |
struct Amazon: Decodable { | |
let amzncode: String | |
let music_quality: String | |
let stanley: String | |
} | |
struct DecodingHelper { | |
private struct Key: CodingKey { | |
let stringValue: String | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
self.intValue = nil | |
} | |
let intValue: Int? | |
init?(intValue: Int) { | |
return nil | |
} | |
} | |
private struct ModelResponse<NestedModel: Decodable>: Decodable { | |
let nested: NestedModel | |
public init(from decoder: Decoder) throws { | |
// Split nested paths with '.' | |
var keyPaths = (decoder.userInfo[CodingUserInfoKey(rawValue: "my_model_key")!]! as! String).split(separator: ".") | |
// Get last key to extract in the end | |
let lastKey = String(keyPaths.popLast()!) | |
// Loop getting container until reach final one | |
var targetContainer = try decoder.container(keyedBy: Key.self) | |
for k in keyPaths { | |
let key = Key(stringValue: String(k))! | |
targetContainer = try targetContainer.nestedContainer(keyedBy: Key.self, forKey: key) | |
} | |
nested = try targetContainer.decode(NestedModel.self, forKey: Key(stringValue: lastKey)!) | |
} | |
} | |
static func decode<T: Decodable>(modelType: T.Type, fromKey key: String) throws -> T { | |
// mock data, replace with network response | |
let path = Bundle.main.path(forResource: "test", ofType: "json")! | |
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) | |
let decoder = JSONDecoder() | |
decoder.userInfo[CodingUserInfoKey(rawValue: "my_model_key")!] = key | |
let model = try decoder.decode(ModelResponse<T>.self, from: data).nested | |
return model | |
} | |
} | |
do { | |
let appl = try DecodingHelper.decode(modelType: Applmusic.self, fromKey: "applmusic") | |
let amazon = try DecodingHelper.decode(modelType: Amazon.self, fromKey: "amazon") | |
let spotify = try DecodingHelper.decode(modelType: Spotify.self, fromKey: "spotify") | |
print(appl) | |
print(amazon) | |
print(spotify) | |
let nestedAmazon = try DecodingHelper.decode(modelType: Amazon.self, fromKey: "nest1.nest2") | |
print(nestedAmazon) | |
let nestedNestedAmazon = try DecodingHelper.decode(modelType: Amazon.self, fromKey: "nest1.nest2.nest3") | |
print(nestedNestedAmazon) | |
} catch let error { | |
print(error.localizedDescription) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment