Meta tweaks
This commit is contained in:
parent
6029ac796b
commit
ca813bf449
|
@ -1,3 +1,3 @@
|
|||
language: swift
|
||||
osx_image: xcode11.2
|
||||
osx_image: xcode11.3
|
||||
script: xcodebuild test -project Defaults.xcodeproj -scheme Defaults-macOS
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#if canImport(Combine)
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
|
@ -34,7 +36,7 @@ extension Defaults {
|
|||
_ = subscriber?.receive(change)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Custom Publisher, which is using DefaultsSubscription.
|
||||
*/
|
||||
|
@ -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,26 +112,26 @@ 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)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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()
|
||||
|
@ -221,7 +223,7 @@ extension Defaults {
|
|||
|
||||
return combinedPublisher
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convenience `Publisher` for all `UserDefaults` key change events. A wrapper around the `UserDefaults.didChangeNotification`.
|
||||
|
||||
|
@ -232,7 +234,7 @@ extension Defaults {
|
|||
let publisher =
|
||||
NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification)
|
||||
.map { _ in () }
|
||||
|
||||
|
||||
if initialEvent {
|
||||
return publisher
|
||||
.prepend(())
|
||||
|
@ -243,3 +245,5 @@ extension Defaults {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -344,7 +344,7 @@ final class DefaultsTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 10)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@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, *)
|
||||
func testObserveMultipleOptionalKeysCombine() {
|
||||
|
@ -489,7 +489,7 @@ final class DefaultsTests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 10)
|
||||
}
|
||||
|
||||
|
||||
func testResetKey() {
|
||||
let defaultString1 = "foo1"
|
||||
let defaultString2 = "foo2"
|
||||
|
@ -513,7 +513,7 @@ final class DefaultsTests: XCTestCase {
|
|||
XCTAssertEqual(Defaults[key3].value, defaultString3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testResetKeyArray() {
|
||||
let defaultString1 = "foo1"
|
||||
let defaultString2 = "foo2"
|
||||
|
@ -532,7 +532,7 @@ final class DefaultsTests: XCTestCase {
|
|||
XCTAssertEqual(Defaults[key2], defaultString2)
|
||||
XCTAssertEqual(Defaults[key3], newString3)
|
||||
}
|
||||
|
||||
|
||||
func testResetOptionalKey() {
|
||||
let newString1 = "bar1"
|
||||
let newString2 = "bar2"
|
||||
|
@ -552,7 +552,7 @@ final class DefaultsTests: XCTestCase {
|
|||
XCTAssertEqual(Defaults[key3], nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testResetOptionalKeyArray() {
|
||||
let newString1 = "bar1"
|
||||
let newString2 = "bar2"
|
||||
|
|
|
@ -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).
|
||||
|
@ -462,7 +464,7 @@ Available on macOS 10.15+, iOS 13.0+, tvOS 13.0+, and watchOS 6.0+.
|
|||
Defaults.publisherAll(initialEvent: Bool = true) -> AnyPublisher<UserDefaults, Never>
|
||||
```
|
||||
|
||||
Convenience [Publisher](https://developer.apple.com/documentation/combine/publisher) for all `UserDefaults` key change events. A wrapper around the [`UserDefaults.didChangeNotification` notification](https://developer.apple.com/documentation/foundation/userdefaults/1408206-didchangenotification).
|
||||
Convenience [Publisher](https://developer.apple.com/documentation/combine/publisher) for all `UserDefaults` key change events. A wrapper around the [`UserDefaults.didChangeNotification` notification](https://developer.apple.com/documentation/foundation/userdefaults/1408206-didchangenotification).
|
||||
|
||||
- Parameter `initialEvent`: Trigger an initial event immediately.
|
||||
|
||||
|
|
Loading…
Reference in New Issue