Improve documentation
This commit is contained in:
parent
35943225a0
commit
60013d90e2
|
@ -11,7 +11,7 @@ extension Defaults {
|
|||
|
||||
`get` will deserialize the internal value to the type that user specify in the function parameter.
|
||||
|
||||
```
|
||||
```swift
|
||||
let any = Defaults.Key<Defaults.AnySerializable>("independentAnyKey", default: 121_314)
|
||||
|
||||
print(Defaults[any].get(Int.self))
|
||||
|
@ -20,7 +20,7 @@ extension Defaults {
|
|||
|
||||
- Note: The only way to assign a non-serializable value is using `ExpressibleByArrayLiteral` or `ExpressibleByDictionaryLiteral` to assign a type that is not a `UserDefaults` natively supported type.
|
||||
|
||||
```
|
||||
```swift
|
||||
private enum mime: String, Defaults.Serializable {
|
||||
case JSON = "application/json"
|
||||
}
|
||||
|
|
|
@ -1,25 +1,9 @@
|
|||
import Foundation
|
||||
|
||||
/**
|
||||
Types that conform to this protocol can be used with `Defaults`.
|
||||
|
||||
The type should have a static variable `bridge` which should reference an instance of a type that conforms to `Defaults.Bridge`.
|
||||
|
||||
```
|
||||
struct User {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
extension User: Defaults.Serializable {
|
||||
static let bridge = UserBridge()
|
||||
}
|
||||
```
|
||||
*/
|
||||
public protocol DefaultsSerializable {
|
||||
public protocol _DefaultsSerializable {
|
||||
typealias Value = Bridge.Value
|
||||
typealias Serializable = Bridge.Serializable
|
||||
associatedtype Bridge: DefaultsBridge
|
||||
associatedtype Bridge: Defaults.Bridge
|
||||
|
||||
/**
|
||||
Static bridge for the `Value` which cannot be stored natively.
|
||||
|
@ -32,59 +16,7 @@ public protocol DefaultsSerializable {
|
|||
static var isNativelySupportedType: Bool { get }
|
||||
}
|
||||
|
||||
/**
|
||||
A `Bridge` is responsible for serialization and deserialization.
|
||||
|
||||
It has two associated types `Value` and `Serializable`.
|
||||
|
||||
- `Value`: The type you want to use.
|
||||
- `Serializable`: The type stored in `UserDefaults`.
|
||||
- `serialize`: Executed before storing to the `UserDefaults` .
|
||||
- `deserialize`: Executed after retrieving its value from the `UserDefaults`.
|
||||
|
||||
```
|
||||
struct User {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
extension User {
|
||||
static let bridge = UserBridge()
|
||||
}
|
||||
|
||||
struct UserBridge: Defaults.Bridge {
|
||||
typealias Value = User
|
||||
typealias Serializable = [String: String]
|
||||
|
||||
func serialize(_ value: Value?) -> Serializable? {
|
||||
guard let value else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [
|
||||
"username": value.username,
|
||||
"password": value.password
|
||||
]
|
||||
}
|
||||
|
||||
func deserialize(_ object: Serializable?) -> Value? {
|
||||
guard
|
||||
let object,
|
||||
let username = object["username"],
|
||||
let password = object["password"]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return User(
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
public protocol DefaultsBridge {
|
||||
public protocol _DefaultsBridge {
|
||||
associatedtype Value
|
||||
associatedtype Serializable
|
||||
|
||||
|
@ -92,45 +24,27 @@ public protocol DefaultsBridge {
|
|||
func deserialize(_ object: Serializable?) -> Value?
|
||||
}
|
||||
|
||||
public protocol DefaultsCollectionSerializable: Collection, Defaults.Serializable {
|
||||
public protocol _DefaultsCollectionSerializable: Collection, Defaults.Serializable {
|
||||
/**
|
||||
`Collection` does not have a initializer, but we need a initializer to convert an array into the `Value`.
|
||||
*/
|
||||
init(_ elements: [Element])
|
||||
}
|
||||
|
||||
public protocol DefaultsSetAlgebraSerializable: SetAlgebra, Defaults.Serializable {
|
||||
public protocol _DefaultsSetAlgebraSerializable: SetAlgebra, Defaults.Serializable {
|
||||
/**
|
||||
Since `SetAlgebra` protocol does not conform to `Sequence`, we cannot convert a `SetAlgebra` to an `Array` directly.
|
||||
*/
|
||||
func toArray() -> [Element]
|
||||
}
|
||||
|
||||
/**
|
||||
Convenience protocol for `Codable`.
|
||||
*/
|
||||
public protocol DefaultsCodableBridge: Defaults.Bridge where Serializable == String, Value: Codable {}
|
||||
public protocol _DefaultsCodableBridge: Defaults.Bridge where Serializable == String, Value: Codable {}
|
||||
|
||||
/**
|
||||
Ambiguous bridge selector protocol. This lets you select your preferred bridge when there are multiple possibilities.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
enum Interval: Int, Codable, Defaults.Serializable, Defaults.PreferRawRepresentable {
|
||||
case tenMinutes = 10
|
||||
case halfHour = 30
|
||||
case oneHour = 60
|
||||
}
|
||||
```
|
||||
|
||||
By default, if an `enum` conforms to `Codable` and `Defaults.Serializable`, it will use the `CodableBridge`, but by conforming to `Defaults.PreferRawRepresentable`, we can switch the bridge back to `RawRepresentableBridge`.
|
||||
*/
|
||||
public protocol DefaultsPreferRawRepresentable: RawRepresentable {}
|
||||
public protocol DefaultsPreferNSSecureCoding: NSSecureCoding {}
|
||||
public protocol _DefaultsPreferRawRepresentable: RawRepresentable {}
|
||||
public protocol _DefaultsPreferNSSecureCoding: NSSecureCoding {}
|
||||
|
||||
// Essential properties for serializing and deserializing `ClosedRange` and `Range`.
|
||||
public protocol DefaultsRange {
|
||||
public protocol _DefaultsRange {
|
||||
associatedtype Bound: Comparable, Defaults.Serializable
|
||||
|
||||
var lowerBound: Bound { get }
|
||||
|
|
|
@ -2,18 +2,45 @@
|
|||
import Foundation
|
||||
|
||||
public enum Defaults {
|
||||
public typealias Keys = AnyKey
|
||||
public typealias Serializable = DefaultsSerializable
|
||||
public typealias CollectionSerializable = DefaultsCollectionSerializable
|
||||
public typealias SetAlgebraSerializable = DefaultsSetAlgebraSerializable
|
||||
public typealias PreferRawRepresentable = DefaultsPreferRawRepresentable
|
||||
public typealias PreferNSSecureCoding = DefaultsPreferNSSecureCoding
|
||||
public typealias Bridge = DefaultsBridge
|
||||
public typealias RangeSerializable = DefaultsRange & DefaultsSerializable
|
||||
typealias CodableBridge = DefaultsCodableBridge
|
||||
/**
|
||||
Access stored values.
|
||||
|
||||
```swift
|
||||
import Defaults
|
||||
|
||||
extension Defaults.Keys {
|
||||
static let quality = Key<Double>("quality", default: 0.8)
|
||||
}
|
||||
|
||||
// …
|
||||
|
||||
Defaults[.quality]
|
||||
//=> 0.8
|
||||
|
||||
Defaults[.quality] = 0.5
|
||||
//=> 0.5
|
||||
|
||||
Defaults[.quality] += 0.1
|
||||
//=> 0.6
|
||||
|
||||
Defaults[.quality] = "🦄"
|
||||
//=> [Cannot assign value of type 'String' to type 'Double']
|
||||
```
|
||||
*/
|
||||
public static subscript<Value: Serializable>(key: Key<Value>) -> Value {
|
||||
get { key.suite[key] }
|
||||
set {
|
||||
key.suite[key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults {
|
||||
// We cannot use `Key` as the container for keys because of "Static stored properties not supported in generic types".
|
||||
public class AnyKey {
|
||||
/**
|
||||
Type-erased key.
|
||||
*/
|
||||
public class _AnyKey {
|
||||
public typealias Key = Defaults.Key
|
||||
|
||||
public let name: String
|
||||
|
@ -31,8 +58,25 @@ public enum Defaults {
|
|||
suite.removeObject(forKey: name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class Key<Value: Serializable>: AnyKey {
|
||||
extension Defaults {
|
||||
/**
|
||||
Strongly-typed key used to access values.
|
||||
|
||||
You declare the defaults keys upfront with a type and default value.
|
||||
|
||||
```swift
|
||||
import Defaults
|
||||
|
||||
extension Defaults.Keys {
|
||||
static let quality = Key<Double>("quality", default: 0.8)
|
||||
// ^ ^ ^ ^
|
||||
// Key Type UserDefaults name Default value
|
||||
}
|
||||
```
|
||||
*/
|
||||
public final class Key<Value: Serializable>: _AnyKey {
|
||||
/**
|
||||
It will be executed in these situations:
|
||||
|
||||
|
@ -50,7 +94,11 @@ public enum Defaults {
|
|||
|
||||
The `default` parameter should not be used if the `Value` type is an optional.
|
||||
*/
|
||||
public init(_ key: String, default defaultValue: Value, suite: UserDefaults = .standard) {
|
||||
public init(
|
||||
_ key: String,
|
||||
default defaultValue: Value,
|
||||
suite: UserDefaults = .standard
|
||||
) {
|
||||
self.defaultValueGetter = { defaultValue }
|
||||
|
||||
super.init(name: key, suite: suite)
|
||||
|
@ -78,19 +126,30 @@ public enum Defaults {
|
|||
}
|
||||
```
|
||||
|
||||
- Parameter key: The key must be ASCII, not start with `@`, and cannot contain a dot (`.`).
|
||||
|
||||
- Note: This initializer will not set the default value in the actual `UserDefaults`. This should not matter much though. It's only really useful if you use legacy KVO bindings.
|
||||
*/
|
||||
public init(_ key: String, suite: UserDefaults = .standard, default defaultValueGetter: @escaping () -> Value) {
|
||||
public init(
|
||||
_ key: String,
|
||||
suite: UserDefaults = .standard,
|
||||
default defaultValueGetter: @escaping () -> Value
|
||||
) {
|
||||
self.defaultValueGetter = defaultValueGetter
|
||||
|
||||
super.init(name: key, suite: suite)
|
||||
}
|
||||
}
|
||||
|
||||
public static subscript<Value: Serializable>(key: Key<Value>) -> Value {
|
||||
get { key.suite[key] }
|
||||
set {
|
||||
key.suite[key] = newValue
|
||||
/**
|
||||
Create a defaults key with an optional value.
|
||||
|
||||
- Parameter key: The key must be ASCII, not start with `@`, and cannot contain a dot (`.`).
|
||||
*/
|
||||
public convenience init<T>(
|
||||
_ key: String,
|
||||
suite: UserDefaults = .standard
|
||||
) where Value == T? {
|
||||
self.init(key, default: nil, suite: suite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,27 +165,122 @@ extension Defaults {
|
|||
}
|
||||
}
|
||||
|
||||
extension Defaults.Key {
|
||||
/**
|
||||
Create a defaults key.
|
||||
|
||||
- Parameter key: The key must be ASCII, not start with `@`, and cannot contain a dot (`.`).
|
||||
*/
|
||||
public convenience init<T>(_ key: String, suite: UserDefaults = .standard) where Value == T? {
|
||||
self.init(key, default: nil, suite: suite)
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults.AnyKey: Equatable {
|
||||
public static func == (lhs: Defaults.AnyKey, rhs: Defaults.AnyKey) -> Bool {
|
||||
extension Defaults._AnyKey: Equatable {
|
||||
public static func == (lhs: Defaults._AnyKey, rhs: Defaults._AnyKey) -> Bool {
|
||||
lhs.name == rhs.name
|
||||
&& lhs.suite == rhs.suite
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults.AnyKey: Hashable {
|
||||
extension Defaults._AnyKey: Hashable {
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(name)
|
||||
hasher.combine(suite)
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults {
|
||||
public typealias Keys = _AnyKey
|
||||
|
||||
/**
|
||||
Types that conform to this protocol can be used with `Defaults`.
|
||||
|
||||
The type should have a static variable `bridge` which should reference an instance of a type that conforms to `Defaults.Bridge`.
|
||||
|
||||
```swift
|
||||
struct User {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
extension User: Defaults.Serializable {
|
||||
static let bridge = UserBridge()
|
||||
}
|
||||
```
|
||||
*/
|
||||
public typealias Serializable = _DefaultsSerializable
|
||||
|
||||
public typealias CollectionSerializable = _DefaultsCollectionSerializable
|
||||
public typealias SetAlgebraSerializable = _DefaultsSetAlgebraSerializable
|
||||
|
||||
/**
|
||||
Ambiguous bridge selector protocol that lets you select your preferred bridge when there are multiple possibilities.
|
||||
|
||||
```swift
|
||||
enum Interval: Int, Codable, Defaults.Serializable, Defaults.PreferRawRepresentable {
|
||||
case tenMinutes = 10
|
||||
case halfHour = 30
|
||||
case oneHour = 60
|
||||
}
|
||||
```
|
||||
|
||||
By default, if an `enum` conforms to `Codable` and `Defaults.Serializable`, it will use the `CodableBridge`, but by conforming to `Defaults.PreferRawRepresentable`, we can switch the bridge back to `RawRepresentableBridge`.
|
||||
*/
|
||||
public typealias PreferRawRepresentable = _DefaultsPreferRawRepresentable
|
||||
|
||||
/**
|
||||
Ambiguous bridge selector protocol that lets you select your preferred bridge when there are multiple possibilities.
|
||||
*/
|
||||
public typealias PreferNSSecureCoding = _DefaultsPreferNSSecureCoding
|
||||
|
||||
/**
|
||||
A `Bridge` is responsible for serialization and deserialization.
|
||||
|
||||
It has two associated types `Value` and `Serializable`.
|
||||
|
||||
- `Value`: The type you want to use.
|
||||
- `Serializable`: The type stored in `UserDefaults`.
|
||||
- `serialize`: Executed before storing to the `UserDefaults` .
|
||||
- `deserialize`: Executed after retrieving its value from the `UserDefaults`.
|
||||
|
||||
```swift
|
||||
struct User {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
extension User {
|
||||
static let bridge = UserBridge()
|
||||
}
|
||||
|
||||
struct UserBridge: Defaults.Bridge {
|
||||
typealias Value = User
|
||||
typealias Serializable = [String: String]
|
||||
|
||||
func serialize(_ value: Value?) -> Serializable? {
|
||||
guard let value else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [
|
||||
"username": value.username,
|
||||
"password": value.password
|
||||
]
|
||||
}
|
||||
|
||||
func deserialize(_ object: Serializable?) -> Value? {
|
||||
guard
|
||||
let object,
|
||||
let username = object["username"],
|
||||
let password = object["password"]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return User(
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
public typealias Bridge = _DefaultsBridge
|
||||
|
||||
public typealias RangeSerializable = _DefaultsRange & _DefaultsSerializable
|
||||
|
||||
/**
|
||||
Convenience protocol for `Codable`.
|
||||
*/
|
||||
typealias CodableBridge = _DefaultsCodableBridge
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# ``Defaults``
|
||||
|
||||
Store key-value pairs persistently across launches of your app.
|
||||
|
||||
It uses [`UserDefaults`](https://developer.apple.com/documentation/foundation/userdefaults) underneath but exposes a type-safe facade with lots of nice conveniences.
|
||||
|
||||
## Usage
|
||||
|
||||
You declare the defaults keys upfront with a type and default value.
|
||||
|
||||
```swift
|
||||
import Defaults
|
||||
|
||||
extension Defaults.Keys {
|
||||
static let quality = Key<Double>("quality", default: 0.8)
|
||||
// ^ ^ ^ ^
|
||||
// Key Type UserDefaults name Default value
|
||||
}
|
||||
```
|
||||
|
||||
You can then access it as a subscript on the `Defaults` global:
|
||||
|
||||
```swift
|
||||
Defaults[.quality]
|
||||
//=> 0.8
|
||||
|
||||
Defaults[.quality] = 0.5
|
||||
//=> 0.5
|
||||
```
|
||||
|
||||
[Learn More](https://github.com/sindresorhus/Defaults#usage)
|
||||
|
||||
## Topics
|
||||
|
||||
### Essentials
|
||||
|
||||
- ``Defaults/subscript(_:)``
|
||||
- ``Defaults/Key``
|
||||
- ``Defaults/Serializable``
|
||||
|
||||
### Methods
|
||||
|
||||
- ``Defaults/reset(_:)-7jv5v``
|
||||
- ``Defaults/reset(_:)-7es1e``
|
||||
- ``Defaults/removeAll(suite:)``
|
||||
|
||||
### SwiftUI
|
||||
|
||||
- ``Default``
|
||||
- ``Defaults/Toggle``
|
||||
|
||||
### Events
|
||||
|
||||
- ``Defaults/publisher(_:options:)``
|
||||
- ``Defaults/publisher(keys:options:)``
|
||||
|
||||
### Force Type Resolution
|
||||
|
||||
- ``Defaults/PreferRawRepresentable``
|
||||
- ``Defaults/PreferNSSecureCoding``
|
|
@ -8,7 +8,7 @@ extension Defaults {
|
|||
/**
|
||||
Migrate the given key's value from JSON string to `Value`.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let array = Key<Set<String>?>("array")
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ import Foundation
|
|||
import CoreGraphics
|
||||
|
||||
extension Defaults {
|
||||
public typealias NativeType = DefaultsNativeType
|
||||
public typealias CodableType = DefaultsCodableType
|
||||
public typealias NativeType = _DefaultsNativeType
|
||||
public typealias CodableType = _DefaultsCodableType
|
||||
}
|
||||
|
||||
extension Data: Defaults.NativeType {
|
||||
|
|
|
@ -9,7 +9,7 @@ It should have an associated type name `CodableForm` where its protocol conform
|
|||
|
||||
So we can convert the JSON string into a `NativeType` like this:
|
||||
|
||||
```
|
||||
```swift
|
||||
guard
|
||||
let jsonData = string?.data(using: .utf8),
|
||||
let codable = try? JSONDecoder().decode(NativeType.CodableForm.self, from: jsonData)
|
||||
|
@ -20,7 +20,7 @@ else {
|
|||
return codable.toNative()
|
||||
```
|
||||
*/
|
||||
public protocol DefaultsNativeType: Defaults.Serializable {
|
||||
public protocol _DefaultsNativeType: Defaults.Serializable {
|
||||
associatedtype CodableForm: Defaults.CodableType
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ Represents the type before migration an its protocol should conform to `Codable`
|
|||
|
||||
The main purposed of `CodableType` is trying to infer the `Codable` type to do `JSONDecoder().decode`. It should have an associated type name `NativeForm` which is the type we want it to store in `UserDefaults`. nd it also have a `toNative()` function to convert itself into `NativeForm`.
|
||||
|
||||
```
|
||||
```swift
|
||||
struct User {
|
||||
username: String
|
||||
password: String
|
||||
|
@ -55,7 +55,7 @@ extension CodableUser: Defaults.CodableType {
|
|||
}
|
||||
```
|
||||
*/
|
||||
public protocol DefaultsCodableType: Codable {
|
||||
public protocol _DefaultsCodableType: Codable {
|
||||
associatedtype NativeForm: Defaults.NativeType
|
||||
func toNative() -> NativeForm
|
||||
}
|
||||
|
|
|
@ -19,19 +19,19 @@ extension UserDefaults {
|
|||
|
||||
1. If `Value` is `[String]`, `Value.CodableForm` will covert into `[String].CodableForm`.
|
||||
|
||||
```
|
||||
```swift
|
||||
JSONDecoder().decode([String].CodableForm.self, from: jsonData)
|
||||
```
|
||||
|
||||
2. If `Array` conforms to `NativeType`, its `CodableForm` is `[Element.CodableForm]` and `Element` is `String`.
|
||||
|
||||
```
|
||||
```swift
|
||||
JSONDecoder().decode([String.CodableForm].self, from: jsonData)
|
||||
```
|
||||
|
||||
3. `String`'s `CodableForm` is `self`, because `String` is `Codable`.
|
||||
|
||||
```
|
||||
```swift
|
||||
JSONDecoder().decode([String].self, from: jsonData)
|
||||
```
|
||||
*/
|
||||
|
|
|
@ -74,7 +74,7 @@ extension Defaults {
|
|||
/**
|
||||
Returns a type-erased `Publisher` that publishes changes related to the given key.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ extension Defaults {
|
|||
*/
|
||||
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, iOSApplicationExtension 13.0, macOSApplicationExtension 10.15, tvOSApplicationExtension 13.0, watchOSApplicationExtension 6.0, *)
|
||||
public static func publisher(
|
||||
keys: AnyKey...,
|
||||
keys: _AnyKey...,
|
||||
options: ObservationOptions = [.initial]
|
||||
) -> AnyPublisher<Void, Never> {
|
||||
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Foundation
|
||||
|
||||
public protocol DefaultsObservation: AnyObject {
|
||||
public protocol _DefaultsObservation: AnyObject {
|
||||
func invalidate()
|
||||
|
||||
/**
|
||||
Keep this observation alive for as long as, and no longer than, another object exists.
|
||||
|
||||
```
|
||||
```swift
|
||||
Defaults.observe(.xyz) { [unowned self] change in
|
||||
self.xyz = change.newValue
|
||||
}.tieToLifetime(of: self)
|
||||
|
@ -25,7 +25,7 @@ public protocol DefaultsObservation: AnyObject {
|
|||
}
|
||||
|
||||
extension Defaults {
|
||||
public typealias Observation = DefaultsObservation
|
||||
public typealias Observation = _DefaultsObservation
|
||||
|
||||
public enum ObservationOption {
|
||||
/**
|
||||
|
@ -95,7 +95,7 @@ extension Defaults {
|
|||
|
||||
- Note: This only works with `Defaults.observe()` and `Defaults.publisher()`. User-made KVO will not be affected.
|
||||
|
||||
```
|
||||
```swift
|
||||
let observer = Defaults.observe(keys: .key1, .key2) {
|
||||
// …
|
||||
|
||||
|
@ -283,7 +283,7 @@ extension Defaults {
|
|||
/**
|
||||
Observe a defaults key.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ extension Defaults {
|
|||
/**
|
||||
Observe multiple keys of any type, but without any information about the changes.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let setting1 = Key<Bool>("setting1", default: false)
|
||||
static let setting2 = Key<Bool>("setting2", default: true)
|
||||
|
@ -324,7 +324,7 @@ extension Defaults {
|
|||
```
|
||||
*/
|
||||
public static func observe(
|
||||
keys: AnyKey...,
|
||||
keys: _AnyKey...,
|
||||
options: ObservationOptions = [.initial],
|
||||
handler: @escaping () -> Void
|
||||
) -> Observation {
|
||||
|
|
|
@ -9,7 +9,7 @@ extension Defaults {
|
|||
- Parameter keys: String keys to reset.
|
||||
- Parameter suite: `UserDefaults` suite.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ extension Defaults {
|
|||
- Parameter keys: String keys to reset.
|
||||
- Parameter suite: `UserDefaults` suite.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ extension Defaults {
|
|||
/**
|
||||
Reset the given keys back to their default values.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -76,14 +76,14 @@ extension Defaults {
|
|||
//=> false
|
||||
```
|
||||
*/
|
||||
public static func reset(_ keys: AnyKey...) {
|
||||
public static func reset(_ keys: _AnyKey...) {
|
||||
reset(keys)
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the given keys back to their default values.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ extension Defaults {
|
|||
//=> false
|
||||
```
|
||||
*/
|
||||
public static func reset(_ keys: [AnyKey]) {
|
||||
public static func reset(_ keys: [_AnyKey]) {
|
||||
for key in keys {
|
||||
key.reset()
|
||||
}
|
||||
|
|
|
@ -62,6 +62,11 @@ extension Defaults {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Access stored values from SwiftUI.
|
||||
|
||||
This is similar to `@AppStorage` but it accepts a ``Defaults/Key`` and many more types.
|
||||
*/
|
||||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
@propertyWrapper
|
||||
public struct Default<Value: Defaults.Serializable>: DynamicProperty {
|
||||
|
@ -77,7 +82,7 @@ public struct Default<Value: Defaults.Serializable>: DynamicProperty {
|
|||
|
||||
- Important: You cannot use this in an `ObservableObject`. It's meant to be used in a `View`.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let hasUnicorn = Key<Bool>("hasUnicorn", default: false)
|
||||
}
|
||||
|
@ -126,7 +131,7 @@ public struct Default<Value: Defaults.Serializable>: DynamicProperty {
|
|||
/**
|
||||
Reset the key back to its default value.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let opacity = Key<Double>("opacity", default: 1)
|
||||
}
|
||||
|
@ -158,11 +163,11 @@ extension Default where Value: Equatable {
|
|||
@available(macOS 11, iOS 14, tvOS 14, watchOS 7, *)
|
||||
extension Defaults {
|
||||
/**
|
||||
Creates a SwiftUI `Toggle` view that is connected to a `Defaults` key with a `Bool` value.
|
||||
A SwiftUI `Toggle` view that is connected to a ``Defaults/Key`` with a `Bool` value.
|
||||
|
||||
The toggle works exactly like the SwiftUI `Toggle`.
|
||||
|
||||
```
|
||||
```swift
|
||||
extension Defaults.Keys {
|
||||
static let showAllDayEvents = Key<Bool>("showAllDayEvents", default: false)
|
||||
}
|
||||
|
@ -176,7 +181,7 @@ extension Defaults {
|
|||
|
||||
You can also listen to changes:
|
||||
|
||||
```
|
||||
```swift
|
||||
struct ShowAllDayEventsSetting: View {
|
||||
var body: some View {
|
||||
Defaults.Toggle("Show All-Day Events", key: .showAllDayEvents)
|
||||
|
|
|
@ -59,7 +59,7 @@ final class LifetimeAssociation {
|
|||
|
||||
When either the owner or the new `LifetimeAssociation` is destroyed, the given deinit handler, if any, is called.
|
||||
|
||||
```
|
||||
```swift
|
||||
class Ghost {
|
||||
var association: LifetimeAssociation?
|
||||
|
||||
|
@ -159,7 +159,7 @@ extension Defaults.Serializable {
|
|||
|
||||
Converts a natively supported type from `UserDefaults` into `Self`.
|
||||
|
||||
```
|
||||
```swift
|
||||
guard let anyObject = object(forKey: key) else {
|
||||
return nil
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ extension Defaults.Serializable {
|
|||
|
||||
Converts `Self` into `UserDefaults` native support type.
|
||||
|
||||
```
|
||||
```swift
|
||||
set(Value.toSerialize(value), forKey: key)
|
||||
```
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Store key-value pairs persistently across launches of your app.
|
||||
|
||||
It uses `NSUserDefaults` underneath but exposes a type-safe facade with lots of nice conveniences.
|
||||
It uses `UserDefaults` underneath but exposes a type-safe facade with lots of nice conveniences.
|
||||
|
||||
It's used in production by apps like [Gifski](https://github.com/sindresorhus/Gifski), [Dato](https://sindresorhus.com/dato), [Lungo](https://sindresorhus.com/lungo), [Battery Indicator](https://sindresorhus.com/battery-indicator), and [HEIC Converter](https://sindresorhus.com/heic-converter).
|
||||
|
||||
|
@ -78,12 +78,13 @@ If a type conforms to both `NSSecureCoding` and `Codable`, then `Codable` will b
|
|||
|
||||
## Usage
|
||||
|
||||
You declare the defaults keys upfront with type and default value.
|
||||
[API documentation.](https://swiftpackageindex.com/sindresorhus/Defaults/documentation/defaults)
|
||||
|
||||
You declare the defaults keys upfront with a type and default value.
|
||||
|
||||
**The key name must be ASCII, not start with `@`, and cannot contain a dot (`.`).**
|
||||
|
||||
```swift
|
||||
import Cocoa
|
||||
import Defaults
|
||||
|
||||
extension Defaults.Keys {
|
||||
|
|
Loading…
Reference in New Issue