Home

Awesome

This project is currently in beta and APIs are subject to change.

GenericID

platforms supports swift codebeat badge

A Swift extension to use string-based API in a type-safe way.

All these fantastic API are compatible with traditional string-based API.

Requirements

Type-safe UserDefaults

You can use NSUbiquitousKeyValueStore with almost the same API.

1. Define your keys

extension UserDefaults.DefaultKeys {
    static let intKey   = Key<Int>("intKey")
    static let colorKey = Key<Color>("colorKey", transformer: .keyedArchive)
    static let pointKey = Key<CGPoint>("pointKey", transformer: .json)
}

2. Have fun!

let ud = UserDefaults.standard

// Get & Set
let value = ud[.intKey]
ud[.stringKey] = "foo"

// Modify
ud[.intKey] += 1
ud[.stringKey] += "bar"

// Typed array
ud[.stringArrayKey].contains("foo")
ud[.intArrayKey][0] += 1

// Work with NSKeyedArchiver
ud[.colorKey] = UIColor.orange
ud[.colorKey]?.redComponent

// Work with JSONEncoder
ud[.pointKey] = CGPoint(x: 1, y: 1)
ud[.pointKey]?.x += 1

// Modern Key-Value Observing
let observation = defaults.observe(.someKey, options: [.old, .new]) { (defaults, change) in
    print(change.newValue)
}

// KVO with deserializer
let observation = defaults.observe(.rectKey, options: [.old, .new]) { (defaults, change) in
    // deserialized automatically
    if let rect = change.newValue {
        someView.frame = rect
    }
}

// Register with serializer
ud.register(defaults: [
    .intKey: 42,
    .stringKey: "foo",
    .colorKey: UIColor.blue, // serialized automatically
    .pointKey: CGPoint(x: 1, y: 1),
])

Default value

If associated type of a key conforms DefaultConstructible, a default value will be constructed for nil result.

public protocol DefaultConstructible {
    init()
}

Here's types that conforms DefaultConstructible and its default value:

TypeDefault value
Boolfalse
Int0
Float/Double0.0
String""
Data[empty data]
Array[]
Dictionary[:]
Optionalnil

Note: Optional also conforms DefaultConstructible, therefore a key typed as DefaultKey<Any?> aka DefaultKey<Optional<Any>> will still returns nil, which is the result of default construction of Optional.

You can always associate an optional type if you want an optional value.

<!--### Observing-->

Type-safe UITableViewCell / UICollectionViewCell

1. Define your reuse identifiers

extension UITableView.CellReuseIdentifiers {
    static let customCell : ID<MyCustomCell> = "CustomCellReuseIdentifier"
}

2. Register your cells

tableView.register(id: .customCell)

3. Dequeue your cells

let cell = tableView.dequeueReusableCell(withIdentifier: .customCell, for: indexPath)
// Typed as MyCustomCell

XIB-based cells

// That's it!
extension MyCustomCell: UINibFromTypeGettable

// Or, incase your nib name is not the same as class name
extension MyCustomCell: UINibGettable {
    static var nibName = "MyNibName"
}

// Then register
tableView.registerNib(id: .customCell)

Type-safe Storyboard

1. Define your storyboards identifiers

extension UIStoryboard.Identifiers {
    static let customVC: ID<MyCustomViewController> = "CustomVCStoryboardIdentifier"
}

2. Use It!

// Also extend to get main storyboard
let sb = UIStoryboard.main()

let vc = sb.instantiateViewController(withIdentifier: .customVC)
// Typed as MyCustomViewController

Type-safe Associated Object

// Define your associate keys
extension YourClass.AssociateKeys {
    static let someKey: Key<Int> = "someKey"
}

// Use it!
yourObject[.someKey] = 42

License

GenericID is available under the MIT license. See the LICENSE file.