A Swift library for serializing Codable
types to and from Any
and UserDefaults
.
RawRepresentable
types are encoded to their raw value:
// "fish"
let any = try KeyValueEncoder().encode(Food(rawValue: "fish"))
Collection
types are encoded to [Any]
:
// ["fish", "chips"]
let any = try KeyValueEncoder().encode(["fish", "chips"])
Structs and classes are encoded to [String: Any]
:
struct User: Codable {
var id: Int
var name: String
}
// ["id": 1, "name": "Herbert"]
let any = try KeyValueEncoder().encode(User(id: 1, name: "Herbert"))
Decode values from Any
:
let food = try KeyValueDecoder().decode(Food.self, from: "fish")
let meals = try KeyValueDecoder().decode([String].self, from: ["fish", "chips"])
let user = try KeyValueDecoder().decode(User.self, from: ["id": 1, "name": "Herbert"])
DecodingError
is thrown when decoding fails. Context
includes a keyPath to the failed property.
// throws DecodingError.typeMismatch 'Expected String at SELF[1], found Int'
let meals = try KeyValueDecoder().decode([String].self, from: ["fish", 1])
// throws DecodingError.valueNotFound 'Expected String at SELF[1].name, found nil'
let user = try KeyValueDecoder().decode(User.self, from: [["id": 1, "name": "Herbert"], ["id:" 2])
// throws DecodingError.typeMismatch 'Int at SELF[2], cannot be exactly represented by UInt8'
let ascii = try KeyValueDecoder().decode([UInt8].self, from: [10, 100, 1000])
The encoding of Optional.none
can be adjusted by setting the strategy.
The default strategy preserves Optional.none
:
let encoder = KeyValueEncoder()
encoder.nilEncodingStrategy = .default
// [1, 2, nil, 3]
let any = try encoder.encode([1, 2, Int?.none, 3])
Compatibility with PropertyListEncoder
is preserved using a placeholder string:
encoder.nilEncodingStrategy = .stringNull
// [1, 2, "$null", 3]
let any = try encoder.encode([1, 2, Int?.none, 3])
Compatibility with JSONSerialization
is preserved using NSNull
:
encoder.nilEncodingStrategy = .nsNull
// [1, 2, NSNull(), 3]
let any = try encoder.encode([1, 2, Int?.none, 3])
Nil values can also be completely removed:
encoder.nilEncodingStrategy = .removed
// [1, 2, 3]
let any = try encoder.encode([1, 2, Int?.none, 3])
Encode and decode Codable
types with UserDefaults
:
try UserDefaults.standard.encode(
User(id: "1", name: "Herbert"),
forKey: "owner"
)
try UserDefaults.standard.encode(
URL(string: "fish.com"),
forKey: "url"
)
try UserDefaults.standard.encode(
Duration.nanoseconds(1),
forKey: "duration"
)
Values are persisted in a friendly representation of plist native types:
let defaults = UserDefaults.standard.dictionaryRepresentation()
[
"owner": ["id": 1, "name": "Herbert"],
"url": URL(string: "fish.com"),
"duration": [0, 1000000000]
]
Decode values from the defaults:
let owner = try UserDefaults.standard.decode(Person.self, forKey: "owner")
let url = try UserDefaults.standard.decode(URL.self, forKey: "url")
let duration = try UserDefaults.standard.decode(Duration.self, forKey: "duration")