KeyValueCoder

0.4.0

A Swift library for serializing Codable types to and from [String: Any] and UserDefaults.
swhitty/KeyValueCoder

What's New

Swift 5.10

2024-03-08T22:05:35Z

Enables .enableExperimentalFeature("StrictConcurrency") and fixes warnings for Swift 5.10

Build CodeCov Swift 5.9 License Twitter

KeyValueCoder

A Swift library for serializing Codable types to and from Any and UserDefaults.

Usage

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])

Nil Encoding/Decoding Strategy

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])

UserDefaults

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")

Description

  • Swift Tools 5.8.0
View More Packages from this Author

Dependencies

  • None
Last updated: Thu Jun 27 2024 17:26:26 GMT-0900 (Hawaii-Aleutian Daylight Time)