Codable
Codable
Tool
Quickly type JSON structs for Swift or any other languages. Network Models
https://app.quicktype.io/
UserDefaults
Codable Property Wrapper
On iOS 12 and prior, primitive types (Int, Double, Bool, etc), while Codable
as a property of a Codable type, cannot itself be JSON encodable. Trying encoding/decoding with these types on iOS 12 earlier platforms will throw an error.
To remedy this behavior we wrap the Codable value in a simple Codable struct.
User Defaults example usage
@propertyWrapper
public struct UserDefaultsBacked<Value: Codable> {
private let key: String
private let defaultValue: Value
private let domain: UserDefaults
public var wrappedValue: Value { }
public init(key: String, defaultValue: Value, domain: UserDefaults = .standard) {
self.key = key
self.defaultValue = defaultValue
self.domain = domain
}
struct Wrapper<Value>: Codable where Value: Codable {
let value: Value
}
// Wrapped value
// GET
do {
let wrappedValue = try JSONDecoder().decode(Wrapper<Value>.self, from: data)
return wrappedValue.value
}
// SET
set {
do {
let data = try JSONEncoder().encode(Wrapper(value: newValue))
domain.setValue(data, forKey: key)
} catch {}
}
Decoder
Snake case issue
ERROR: keyNotFound(CodingKeys(stringValue: "iso_3166_1", intValue: nil)
Just use
.convertFromSnakeCase for decoder strategy
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
SO | swiftui-get-error-when-decoding-json-data-which-includes-key-name-as-iso
The data couldn’t be read because it isn’t in the correct format.
dataCorrupted(Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "", intValue: 0), CodingKeys(stringValue: "TestKey", intValue: nil)], debugDescription: "Cannot initialize TestKey from invalid String value TestValue", underlyingError: nil))
This probably happen because the API changed few things on their backend and you should have had optional initializers rather than concrete tie-ins. this resulted in full failure from the client consumer side of things and it led to your app / software in broken state. Very bad design but I was working around a POC and I just wanted to build something quickly.
Troubleshooting coding / decoding errors
When using JSONDecoder or .decode() functions, make sure you have do try catch added explicitly so that it doesn't fail silently with those JSON coding / decoding views.
Make sure to use String(describing:) as well instead of .localizedDescriptions
do {
let decoded = try JSONDecoder().decode([Struct].self, from: data!)
} catch {
// print(error.localizedDescription) // <- ⚠️ Don't use this!
print(String(describing: error)) // <- ✅ Use this for debuging!
}
Enums with Raw value
json decoder | dictionary coding as array
Swift only decodes a JSON object {} into a Dictionary if the key is exactly String or Int.
For any other key type—even an enum that is String-backed—the decoder expects an unkeyed container (a JSON Array []) with alternating keys and values.
- Expectation:
["sky-uk-dev", { ... }, "comcast", { ... }] - Reality: Your JSON is
{ "sky-uk-dev": { ... } }
Since your JSON uses { }, the decoder sees a dictionary and throws the typeMismatch error because it was looking for that alternating array.
The Fix: CodingKeyRepresentable
If you are on Swift 5.6+, you can fix this by adding CodingKeyRepresentable to your enum. This tells Swift to treat the enum as a valid dictionary key.
swift
public enum PartnerID: String, Codable, CodingKeyRepresentable {
case skyDev = "sky-uk-dev"
case sky = "sky-uk"
// ... rest of cases
}