An open API service indexing awesome lists of open source software.

https://github.com/edonv/user-default-entries

SwiftUI property wrapper for type-safe and key-safe use of UserDefaults.
https://github.com/edonv/user-default-entries

propertywrapper swift swiftui userdefaults

Last synced: about 15 hours ago
JSON representation

SwiftUI property wrapper for type-safe and key-safe use of UserDefaults.

Awesome Lists containing this project

README

          

# User Default Entries

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fedonv%2Fuser-default-entries%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/edonv/user-default-entries)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fedonv%2Fuser-default-entries%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/edonv/user-default-entries)

## Usage

```swift
.package(url: "https://github.com/edonv/user-default-entries.git", from: "0.0.0")
```

```swift
.product(name: "UserDefault", package: "user-default-entries")
```

### Macro vs Manual

To use the `@UserDefault` property wrapper, you need to have added a `get`/`set` property to `UserDefaults` via an extension. These can be defined manually or with the packaged `@DefaultEntry` macro.

Macro:

```swift
import DefaultEntry

extension UserDefaults {
@DefaultEntry(default: "defaultValue")
var exampleWithDefault: String

@DefaultEntry
var exampleWithoutDefault: String?

@DefaultEntry(default: 123)
var exampleIntWithDefault: Int

@DefaultEntry(prefixedWith: "customPrefix_")
var exampleIntWithoutDefault: Int?
}
```

would be equivalent to the following output:

```swift
extension UserDefaults {
var exampleWithDefault: String {
get { String(withKey: "key_exampleWithDefault", in: self) ?? "defaultValue" }
set { newValue.store(in: self, withKey: "key_exampleWithDefault") }
}

var exampleWithoutDefault: String? {
get { String(withKey: "key_exampleWithoutDefault", in: self) }
set { newValue.store(in: self, withKey: "key_exampleWithoutDefault") }
}

var exampleIntWithDefault: Int {
get { Int(withKey: "key_exampleIntWithDefault", in: self) ?? "defaultValue" }
set { newValue.store(in: self, withKey: "key_exampleValue") }
}

var exampleIntWithoutDefault: Int? {
get { Int(withKey: "customPrefix_exampleIntWithoutDefault", in: self) }
set { newValue.store(in: self, withKey: "customPrefix_exampleIntWithoutDefault") }
}
}
```

Then, in a `SwiftUI` view, you can do the following:

```swift
import SwiftUI
import UserDefault

struct ExampleView: View {
@UserDefault(\.exampleWithDefault)
private var exampleWithDefault // implied to be a String

@UserDefault(\.exampleWithoutDefault)
private var exampleWithoutDefault // implied to be an optional String

var body: some View {
VStack {
TextField("Example Field", text: $exampleWithDefault)

Text(exampleWithoutDefault ?? "Value is empty")
}
}
}
```

### `UserDefaultable`

The `@UserDefault` property wrapper relies on both the `@DefaultEntry` macro (or manual entry) and the `UserDefaultable` protocol. Any type used must conform to `UserDefaultable`. If it's a custom type, it must explicitly conform to `UserDefaultable` and one of `RawRepresentable` or `Codable`. See the following section for more details on those.

### RawRepresentable/Codable

`UserDefaultable` supports types that conform to `RawRepresentable` (whose `RawValue` types conform to `UserDefaultable`) and `Codable`, but due to Swift language restrictions, you still have to explicitly add conformance of `UserDefaultable` to your own type. The protocol requirements will be automatically synthesized for you.

## Notes

### NSNumber

Out of the box, `NSNumber` is supported by `UserDefaults`, but due to Swift language restrictions when it comes to adding initializers for a protocol to an existing non-final class, it's not possible to add `UserDefaultable` conformance to `NSNumber`. I'd recommend using `Int`, `Float`, or `Double` instead.

## To-Do's

- [x] Write a macro equivalent to `@Entry`
- `@UserDefaultsEntry(_ key: String, in userDefaults: UserDefaults? = nil)
- [ ] Add conformance of `UserDefaultable` to `BinaryInteger` and `BinaryFloatingPoint` types.
- [ ] Add DocC content from README.