Meta tweaks

This commit is contained in:
Sindre Sorhus 2020-01-21 00:07:30 +07:00
parent 6029ac796b
commit ca813bf449
7 changed files with 134 additions and 127 deletions

View File

@ -1,3 +1,3 @@
language: swift
osx_image: xcode11.2
osx_image: xcode11.3
script: xcodebuild test -project Defaults.xcodeproj -scheme Defaults-macOS

View File

@ -68,7 +68,7 @@
AD2FAA281CD0B6E100659CF4 /* DefaultsTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultsTests.plist; sourceTree = "<group>"; };
DD75027A1C68FCFC006590AF /* Defaults-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Defaults-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
DD75028D1C690C7A006590AF /* Defaults-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Defaults-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
E286D0C623B8D51100570D1E /* Observation+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Observation+Combine.swift"; sourceTree = "<group>"; };
E286D0C623B8D51100570D1E /* Observation+Combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "Observation+Combine.swift"; sourceTree = "<group>"; usesTabs = 1; };
E3EB3E32216505920033B089 /* util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = util.swift; sourceTree = "<group>"; usesTabs = 1; };
E3EB3E34216507AE0033B089 /* Observation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Observation.swift; sourceTree = "<group>"; usesTabs = 1; };
/* End PBXFileReference section */

View File

@ -16,13 +16,13 @@ public final class Defaults {
fileprivate init() {}
}
public final class Key<T: Codable>: Keys {
public final class Key<Value: Codable>: Keys {
public let name: String
public let defaultValue: T
public let defaultValue: Value
public let suite: UserDefaults
/// Create a defaults key.
public init(_ key: String, default defaultValue: T, suite: UserDefaults = .standard) {
public init(_ key: String, default defaultValue: Value, suite: UserDefaults = .standard) {
self.name = key
self.defaultValue = defaultValue
self.suite = suite
@ -30,7 +30,7 @@ public final class Defaults {
super.init()
// Sets the default value in the actual UserDefaults, so it can be used in other contexts, like binding.
if UserDefaults.isNativelySupportedType(T.self) {
if UserDefaults.isNativelySupportedType(Value.self) {
suite.register(defaults: [key: defaultValue])
} else if let value = suite._encode(defaultValue) {
suite.register(defaults: [key: value])
@ -39,13 +39,13 @@ public final class Defaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public final class NSSecureCodingKey<T: NSSecureCoding>: Keys {
public final class NSSecureCodingKey<Value: NSSecureCoding>: Keys {
public let name: String
public let defaultValue: T
public let defaultValue: Value
public let suite: UserDefaults
/// Create a defaults key.
public init(_ key: String, default defaultValue: T, suite: UserDefaults = .standard) {
public init(_ key: String, default defaultValue: Value, suite: UserDefaults = .standard) {
self.name = key
self.defaultValue = defaultValue
self.suite = suite
@ -53,7 +53,7 @@ public final class Defaults {
super.init()
// Sets the default value in the actual UserDefaults, so it can be used in other contexts, like binding.
if UserDefaults.isNativelySupportedType(T.self) {
if UserDefaults.isNativelySupportedType(Value.self) {
suite.register(defaults: [key: defaultValue])
} else if let value = try? NSKeyedArchiver.archivedData(withRootObject: defaultValue, requiringSecureCoding: true) {
suite.register(defaults: [key: value])
@ -61,7 +61,7 @@ public final class Defaults {
}
}
public final class OptionalKey<T: Codable>: Keys {
public final class OptionalKey<Value: Codable>: Keys {
public let name: String
public let suite: UserDefaults
@ -73,7 +73,7 @@ public final class Defaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public final class NSSecureCodingOptionalKey<T: NSSecureCoding>: Keys {
public final class NSSecureCodingOptionalKey<Value: NSSecureCoding>: Keys {
public let name: String
public let suite: UserDefaults
@ -87,7 +87,7 @@ public final class Defaults {
fileprivate init() {}
/// Access a defaults value using a `Defaults.Key`.
public static subscript<T: Codable>(key: Key<T>) -> T {
public static subscript<Value: Codable>(key: Key<Value>) -> Value {
get { key.suite[key] }
set {
key.suite[key] = newValue
@ -96,7 +96,7 @@ public final class Defaults {
/// Access a defaults value using a `Defaults.NSSecureCodingKey`.
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static subscript<T: NSSecureCoding>(key: NSSecureCodingKey<T>) -> T {
public static subscript<Value: NSSecureCoding>(key: NSSecureCodingKey<Value>) -> Value {
get { key.suite[key] }
set {
key.suite[key] = newValue
@ -104,7 +104,7 @@ public final class Defaults {
}
/// Access a defaults value using a `Defaults.OptionalKey`.
public static subscript<T: Codable>(key: OptionalKey<T>) -> T? {
public static subscript<Value: Codable>(key: OptionalKey<Value>) -> Value? {
get { key.suite[key] }
set {
key.suite[key] = newValue
@ -113,7 +113,7 @@ public final class Defaults {
/// Access a defaults value using a `Defaults.OptionalKey`.
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static subscript<T: NSSecureCoding>(key: NSSecureCodingOptionalKey<T>) -> T? {
public static subscript<Value: NSSecureCoding>(key: NSSecureCodingOptionalKey<Value>) -> Value? {
get { key.suite[key] }
set {
key.suite[key] = newValue
@ -140,7 +140,7 @@ public final class Defaults {
//=> false
```
*/
public static func reset<T: Codable>(_ keys: Key<T>..., suite: UserDefaults = .standard) {
public static func reset<Value: Codable>(_ keys: Key<Value>..., suite: UserDefaults = .standard) {
reset(keys, suite: suite)
}
@ -151,7 +151,7 @@ public final class Defaults {
- Parameter suite: `UserDefaults` suite.
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func reset<T: NSSecureCoding>(_ keys: NSSecureCodingKey<T>..., suite: UserDefaults = .standard) {
public static func reset<Value: NSSecureCoding>(_ keys: NSSecureCodingKey<Value>..., suite: UserDefaults = .standard) {
reset(keys, suite: suite)
}
@ -175,7 +175,7 @@ public final class Defaults {
//=> false
```
*/
public static func reset<T: Codable>(_ keys: [Key<T>], suite: UserDefaults = .standard) {
public static func reset<Value: Codable>(_ keys: [Key<Value>], suite: UserDefaults = .standard) {
for key in keys {
key.suite[key] = key.defaultValue
}
@ -188,7 +188,7 @@ public final class Defaults {
- Parameter suite: `UserDefaults` suite.
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func reset<T: NSSecureCoding>(_ keys: [NSSecureCodingKey<T>], suite: UserDefaults = .standard) {
public static func reset<Value: NSSecureCoding>(_ keys: [NSSecureCodingKey<Value>], suite: UserDefaults = .standard) {
for key in keys {
key.suite[key] = key.defaultValue
}
@ -213,7 +213,7 @@ public final class Defaults {
//=> nil
```
*/
public static func reset<T: Codable>(_ keys: OptionalKey<T>..., suite: UserDefaults = .standard) {
public static func reset<Value: Codable>(_ keys: OptionalKey<Value>..., suite: UserDefaults = .standard) {
reset(keys, suite: suite)
}
@ -225,7 +225,7 @@ public final class Defaults {
```
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func reset<T: NSSecureCoding>(_ keys: NSSecureCodingOptionalKey<T>..., suite: UserDefaults = .standard) {
public static func reset<Value: NSSecureCoding>(_ keys: NSSecureCodingOptionalKey<Value>..., suite: UserDefaults = .standard) {
reset(keys, suite: suite)
}
@ -248,7 +248,7 @@ public final class Defaults {
//=> nil
```
*/
public static func reset<T: Codable>(_ keys: [OptionalKey<T>], suite: UserDefaults = .standard) {
public static func reset<Value: Codable>(_ keys: [OptionalKey<Value>], suite: UserDefaults = .standard) {
for key in keys {
key.suite[key] = nil
}
@ -261,7 +261,7 @@ public final class Defaults {
- Parameter suite: `UserDefaults` suite.
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func reset<T: NSSecureCoding>(_ keys: [NSSecureCodingOptionalKey<T>], suite: UserDefaults = .standard) {
public static func reset<Value: NSSecureCoding>(_ keys: [NSSecureCodingOptionalKey<Value>], suite: UserDefaults = .standard) {
for key in keys {
key.suite[key] = nil
}
@ -278,9 +278,9 @@ public final class Defaults {
}
extension UserDefaults {
private func _get<T: Codable>(_ key: String) -> T? {
if UserDefaults.isNativelySupportedType(T.self) {
return object(forKey: key) as? T
private func _get<Value: Codable>(_ key: String) -> Value? {
if UserDefaults.isNativelySupportedType(Value.self) {
return object(forKey: key) as? Value
}
guard
@ -291,7 +291,7 @@ extension UserDefaults {
}
do {
return (try JSONDecoder().decode([T].self, from: data)).first
return (try JSONDecoder().decode([Value].self, from: data)).first
} catch {
print(error)
}
@ -300,9 +300,9 @@ extension UserDefaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
private func _get<T: NSSecureCoding>(_ key: String) -> T? {
if UserDefaults.isNativelySupportedType(T.self) {
return object(forKey: key) as? T
private func _get<Value: NSSecureCoding>(_ key: String) -> Value? {
if UserDefaults.isNativelySupportedType(Value.self) {
return object(forKey: key) as? Value
}
guard
@ -312,7 +312,7 @@ extension UserDefaults {
}
do {
return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Value
} catch {
print(error)
}
@ -320,7 +320,7 @@ extension UserDefaults {
return nil
}
fileprivate func _encode<T: Codable>(_ value: T) -> String? {
fileprivate func _encode<Value: Codable>(_ value: Value) -> String? {
do {
// Some codable values like URL and enum are encoded as a top-level
// string which JSON can't handle, so we need to wrap it in an array
@ -333,8 +333,8 @@ extension UserDefaults {
}
}
private func _set<T: Codable>(_ key: String, to value: T) {
if UserDefaults.isNativelySupportedType(T.self) {
private func _set<Value: Codable>(_ key: String, to value: Value) {
if UserDefaults.isNativelySupportedType(Value.self) {
set(value, forKey: key)
return
}
@ -343,8 +343,8 @@ extension UserDefaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
private func _set<T: NSSecureCoding>(_ key: String, to value: T) {
if UserDefaults.isNativelySupportedType(T.self) {
private func _set<Value: NSSecureCoding>(_ key: String, to value: Value) {
if UserDefaults.isNativelySupportedType(Value.self) {
set(value, forKey: key)
return
}
@ -352,7 +352,7 @@ extension UserDefaults {
set(try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true), forKey: key)
}
public subscript<T: Codable>(key: Defaults.Key<T>) -> T {
public subscript<Value: Codable>(key: Defaults.Key<Value>) -> Value {
get { _get(key.name) ?? key.defaultValue }
set {
_set(key.name, to: newValue)
@ -360,14 +360,14 @@ extension UserDefaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public subscript<T: NSSecureCoding>(key: Defaults.NSSecureCodingKey<T>) -> T {
public subscript<Value: NSSecureCoding>(key: Defaults.NSSecureCodingKey<Value>) -> Value {
get { _get(key.name) ?? key.defaultValue }
set {
_set(key.name, to: newValue)
}
}
public subscript<T: Codable>(key: Defaults.OptionalKey<T>) -> T? {
public subscript<Value: Codable>(key: Defaults.OptionalKey<Value>) -> Value? {
get { _get(key.name) }
set {
guard let value = newValue else {
@ -380,7 +380,7 @@ extension UserDefaults {
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public subscript<T: NSSecureCoding>(key: Defaults.NSSecureCodingOptionalKey<T>) -> T? {
public subscript<Value: NSSecureCoding>(key: Defaults.NSSecureCodingOptionalKey<Value>) -> Value? {
get { _get(key.name) }
set {
guard let value = newValue else {
@ -392,15 +392,16 @@ extension UserDefaults {
}
}
fileprivate static func isNativelySupportedType<T>(_ type: T.Type) -> Bool {
fileprivate static func isNativelySupportedType<Value>(_ type: Value.Type) -> Bool {
switch type {
case is Bool.Type,
is String.Type,
is Int.Type,
is Double.Type,
is Float.Type,
is Date.Type,
is Data.Type:
case
is Bool.Type,
is String.Type,
is Int.Type,
is Double.Type,
is Float.Type,
is Date.Type,
is Data.Type:
return true
default:
return false

View File

@ -1,3 +1,5 @@
#if canImport(Combine)
import Foundation
import Combine
@ -82,12 +84,12 @@ 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<T: Codable>(
_ key: Defaults.Key<T>,
public static func publisher<Value: Codable>(
_ key: Defaults.Key<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<KeyChange<T>, Never> {
) -> AnyPublisher<KeyChange<Value>, Never> {
let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options)
.map { KeyChange<T>(change: $0, defaultValue: key.defaultValue) }
.map { KeyChange<Value>(change: $0, defaultValue: key.defaultValue) }
return AnyPublisher(publisher)
}
@ -96,12 +98,12 @@ extension Defaults {
Returns a type-erased `Publisher` that publishes changes related to the given key.
*/
@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<T: NSSecureCoding>(
_ key: Defaults.NSSecureCodingKey<T>,
public static func publisher<Value: NSSecureCoding>(
_ key: Defaults.NSSecureCodingKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<NSSecureCodingKeyChange<T>, Never> {
) -> AnyPublisher<NSSecureCodingKeyChange<Value>, Never> {
let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options)
.map { NSSecureCodingKeyChange<T>(change: $0, defaultValue: key.defaultValue) }
.map { NSSecureCodingKeyChange<Value>(change: $0, defaultValue: key.defaultValue) }
return AnyPublisher(publisher)
}
@ -110,12 +112,12 @@ extension Defaults {
Returns a type-erased `Publisher` that publishes changes related to the given optional key.
*/
@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<T: Codable>(
_ key: Defaults.OptionalKey<T>,
public static func publisher<Value: Codable>(
_ key: Defaults.OptionalKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<OptionalKeyChange<T>, Never> {
) -> AnyPublisher<OptionalKeyChange<Value>, Never> {
let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options)
.map { OptionalKeyChange<T>(change: $0) }
.map { OptionalKeyChange<Value>(change: $0) }
return AnyPublisher(publisher)
}
@ -124,12 +126,12 @@ extension Defaults {
Returns a type-erased `Publisher` that publishes changes related to the given optional key.
*/
@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<T: NSSecureCoding>(
_ key: Defaults.NSSecureCodingOptionalKey<T>,
public static func publisher<Value: NSSecureCoding>(
_ key: Defaults.NSSecureCodingOptionalKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<NSSecureCodingOptionalKeyChange<T>, Never> {
) -> AnyPublisher<NSSecureCodingOptionalKeyChange<Value>, Never> {
let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options)
.map { NSSecureCodingOptionalKeyChange<T>(change: $0) }
.map { NSSecureCodingOptionalKeyChange<Value>(change: $0) }
return AnyPublisher(publisher)
}
@ -138,8 +140,8 @@ extension Defaults {
Publisher for multiple `Key<T>` observation, but without specific information about changes.
*/
@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<T: Codable>(
keys: Defaults.Key<T>...,
public static func publisher<Value: Codable>(
keys: Defaults.Key<Value>...,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()
@ -160,8 +162,8 @@ extension Defaults {
Publisher for multiple `OptionalKey<T>` observation, but without specific information about changes.
*/
@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<T: Codable>(
keys: Defaults.OptionalKey<T>...,
public static func publisher<Value: Codable>(
keys: Defaults.OptionalKey<Value>...,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()
@ -182,8 +184,8 @@ extension Defaults {
Publisher for multiple `NSSecureCodingKey<T>` observation, but without specific information about changes.
*/
@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<T: NSSecureCoding>(
keys: Defaults.NSSecureCodingKey<T>...,
public static func publisher<Value: NSSecureCoding>(
keys: Defaults.NSSecureCodingKey<Value>...,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()
@ -204,8 +206,8 @@ extension Defaults {
Publisher for multiple `NSSecureCodingOptionalKey<T>` observation, but without specific information about changes.
*/
@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<T: NSSecureCoding>(
keys: Defaults.NSSecureCodingOptionalKey<T>...,
public static func publisher<Value: NSSecureCoding>(
keys: Defaults.NSSecureCodingOptionalKey<Value>...,
options: NSKeyValueObservingOptions = [.initial, .old, .new]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()
@ -243,3 +245,5 @@ extension Defaults {
}
}
}
#endif

View File

@ -26,7 +26,7 @@ public protocol DefaultsObservation: AnyObject {
}
extension Defaults {
private static func deserialize<T: Decodable>(_ value: Any?, to type: T.Type) -> T? {
private static func deserialize<Value: Decodable>(_ value: Any?, to type: Value.Type) -> Value? {
guard
let value = value,
!(value is NSNull)
@ -35,16 +35,16 @@ extension Defaults {
}
// This handles the case where the value was a plist value using `isNativelySupportedType`
if let value = value as? T {
if let value = value as? Value {
return value
}
// Using the array trick as done below in `UserDefaults#_set()`
return [T].init(jsonString: "\([value])")?.first
return [Value].init(jsonString: "\([value])")?.first
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
private static func deserialize<T: NSSecureCoding>(_ value: Any?, to type: T.Type) -> T? {
private static func deserialize<Value: NSSecureCoding>(_ value: Any?, to type: Value.Type) -> Value? {
guard
let value = value,
!(value is NSNull)
@ -53,7 +53,7 @@ extension Defaults {
}
// This handles the case where the value was a plist value using `isNativelySupportedType`
if let value = value as? T {
if let value = value as? Value {
return value
}
@ -61,7 +61,7 @@ extension Defaults {
return nil
}
return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(dataValue) as? T
return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(dataValue) as? Value
}
final class BaseChange {
@ -80,69 +80,69 @@ extension Defaults {
}
}
public struct KeyChange<T: Codable> {
public struct KeyChange<Value: Codable> {
public let kind: NSKeyValueChange
public let indexes: IndexSet?
public let isPrior: Bool
public let newValue: T
public let oldValue: T
public let newValue: Value
public let oldValue: Value
init(change: BaseChange, defaultValue: T) {
init(change: BaseChange, defaultValue: Value) {
self.kind = change.kind
self.indexes = change.indexes
self.isPrior = change.isPrior
self.oldValue = deserialize(change.oldValue, to: T.self) ?? defaultValue
self.newValue = deserialize(change.newValue, to: T.self) ?? defaultValue
self.oldValue = deserialize(change.oldValue, to: Value.self) ?? defaultValue
self.newValue = deserialize(change.newValue, to: Value.self) ?? defaultValue
}
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public struct NSSecureCodingKeyChange<T: NSSecureCoding> {
public struct NSSecureCodingKeyChange<Value: NSSecureCoding> {
public let kind: NSKeyValueChange
public let indexes: IndexSet?
public let isPrior: Bool
public let newValue: T
public let oldValue: T
public let newValue: Value
public let oldValue: Value
init(change: BaseChange, defaultValue: T) {
init(change: BaseChange, defaultValue: Value) {
self.kind = change.kind
self.indexes = change.indexes
self.isPrior = change.isPrior
self.oldValue = deserialize(change.oldValue, to: T.self) ?? defaultValue
self.newValue = deserialize(change.newValue, to: T.self) ?? defaultValue
self.oldValue = deserialize(change.oldValue, to: Value.self) ?? defaultValue
self.newValue = deserialize(change.newValue, to: Value.self) ?? defaultValue
}
}
public struct OptionalKeyChange<T: Codable> {
public struct OptionalKeyChange<Value: Codable> {
public let kind: NSKeyValueChange
public let indexes: IndexSet?
public let isPrior: Bool
public let newValue: T?
public let oldValue: T?
public let newValue: Value?
public let oldValue: Value?
init(change: BaseChange) {
self.kind = change.kind
self.indexes = change.indexes
self.isPrior = change.isPrior
self.oldValue = deserialize(change.oldValue, to: T.self)
self.newValue = deserialize(change.newValue, to: T.self)
self.oldValue = deserialize(change.oldValue, to: Value.self)
self.newValue = deserialize(change.newValue, to: Value.self)
}
}
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public struct NSSecureCodingOptionalKeyChange<T: NSSecureCoding> {
public struct NSSecureCodingOptionalKeyChange<Value: NSSecureCoding> {
public let kind: NSKeyValueChange
public let indexes: IndexSet?
public let isPrior: Bool
public let newValue: T?
public let oldValue: T?
public let newValue: Value?
public let oldValue: Value?
init(change: BaseChange) {
self.kind = change.kind
self.indexes = change.indexes
self.isPrior = change.isPrior
self.oldValue = deserialize(change.oldValue, to: T.self)
self.newValue = deserialize(change.newValue, to: T.self)
self.oldValue = deserialize(change.oldValue, to: Value.self)
self.newValue = deserialize(change.newValue, to: Value.self)
}
}
@ -223,14 +223,14 @@ extension Defaults {
}
```
*/
public static func observe<T: Codable>(
_ key: Defaults.Key<T>,
public static func observe<Value: Codable>(
_ key: Defaults.Key<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (KeyChange<T>) -> Void
handler: @escaping (KeyChange<Value>) -> Void
) -> DefaultsObservation {
let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in
handler(
KeyChange<T>(change: change, defaultValue: key.defaultValue)
KeyChange<Value>(change: change, defaultValue: key.defaultValue)
)
}
observation.start(options: options)
@ -241,14 +241,14 @@ extension Defaults {
Observe a defaults key.
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func observe<T: NSSecureCoding>(
_ key: Defaults.NSSecureCodingKey<T>,
public static func observe<Value: NSSecureCoding>(
_ key: Defaults.NSSecureCodingKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (NSSecureCodingKeyChange<T>) -> Void
handler: @escaping (NSSecureCodingKeyChange<Value>) -> Void
) -> DefaultsObservation {
let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in
handler(
NSSecureCodingKeyChange<T>(change: change, defaultValue: key.defaultValue)
NSSecureCodingKeyChange<Value>(change: change, defaultValue: key.defaultValue)
)
}
observation.start(options: options)
@ -269,14 +269,14 @@ extension Defaults {
}
```
*/
public static func observe<T: Codable>(
_ key: Defaults.OptionalKey<T>,
public static func observe<Value: Codable>(
_ key: Defaults.OptionalKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (OptionalKeyChange<T>) -> Void
handler: @escaping (OptionalKeyChange<Value>) -> Void
) -> DefaultsObservation {
let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in
handler(
OptionalKeyChange<T>(change: change)
OptionalKeyChange<Value>(change: change)
)
}
observation.start(options: options)
@ -287,14 +287,14 @@ extension Defaults {
Observe an optional defaults key.
*/
@available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, iOSApplicationExtension 11.0, macOSApplicationExtension 10.13, tvOSApplicationExtension 11.0, watchOSApplicationExtension 4.0, *)
public static func observe<T: NSSecureCoding>(
_ key: Defaults.NSSecureCodingOptionalKey<T>,
public static func observe<Value: NSSecureCoding>(
_ key: Defaults.NSSecureCodingOptionalKey<Value>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (NSSecureCodingOptionalKeyChange<T>) -> Void
handler: @escaping (NSSecureCodingOptionalKeyChange<Value>) -> Void
) -> DefaultsObservation {
let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in
handler(
NSSecureCodingOptionalKeyChange<T>(change: change)
NSSecureCodingOptionalKeyChange<Value>(change: change)
)
}
observation.start(options: options)

View File

@ -2,6 +2,8 @@
> Swifty and modern [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults)
**Note:** The readme reflects the master branch. [Click here](https://github.com/sindresorhus/Defaults/tree/55ffea9487fb9b559406d909ee31dcd955fe77aa#readme) for docs for the latest version. The code in the master branch cannot be released until Apple fixes [this bug](https://github.com/feedback-assistant/reports/issues/44).
It uses `NSUserDefaults` 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).