Skip to content

Instantly share code, notes, and snippets.

@aunnnn
Created May 17, 2018 16:14
Show Gist options
  • Save aunnnn/9a6b4608ae49fe1594dbcabd9e607834 to your computer and use it in GitHub Desktop.
Save aunnnn/9a6b4608ae49fe1594dbcabd9e607834 to your computer and use it in GitHub Desktop.
Decodable from nested keys
{
"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"
}
}
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