I have a model TestModel
that encodes data to JSON to send to an API. It looks like this:
// Called by: JSONEncoder().encode(testModelObject)
class TestModel {
enum CodingKeys: String, CodingKey {
case someKey = "some_key"
case otherKey = "other_key"
case thirdKey = "third_key"
case apiID = "id"
// ... lots of other keys
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(someKeyValue, forKey: .someKey)
try container.encode(otherKeyValue, forKey: .otherKey)
try container.encode(thirdKeyValue, forKey: .thirdKey)
// ... lots of other encoded fields
}
}
The above works fine, however sometimes I wish to send a request to a different endpoint that updates just a single attribute. The update is always going to be for the same attribute. At present I'm sending through all data in encode(), which equals a lot of wasted bandwidth.
I'm sure there's an easy way to do this, but docs/google/stackoverflow aren't proving helpful. So: any thoughts on how to create a second encoding strategy along the lines of the below and call it?
func encodeForUpdate(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(apiID, forKey: .apiID)
try container.encode(justOneValueToUpdate, forKey: .someKey)
}
You need to have a single encode(to encoder: Encoder)
function but you can solve this by using a specific CodingKey
enum for the second strategy
enum SimpleCodingKeys: String, CodingKey {
case thirdKey = "third_key"
case apiID = "id"
}
and then use the userInfo
property of JSONEncoder
to tell when you want to use this second enum. First we need a key to use
extension TestModel {
static var useSimpleCodingKeys: CodingUserInfoKey {
return CodingUserInfoKey(rawValue: "useSimpleCodingKeys")!
}
}
and then adjust the encoding function
func encode(to encoder: Encoder) throws {
let useSimple = encoder.userInfo[Self.useSimpleCodingKeys] as? Bool ?? false
if useSimple {
var container = encoder.container(keyedBy: SimpleCodingKeys.self)
try container.encode(apiID, forKey: .apiID)
try container.encode(thirdKeyValue, forKey: .thirdKey)
} else {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(someKeyValue, forKey: .someKey)
try container.encode(otherKeyValue, forKey: .otherKey)
try container.encode(thirdKeyValue, forKey: .thirdKey)
...
}
}
And of course set this value in the dictionary when encoding
let encoder = JSONEncoder()
encoder.userInfo[TestModel.useSimpleCodingKeys] = true