From ca813bf449defc6af60640f9efbcc85ce70b10a9 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 21 Jan 2020 00:07:30 +0700 Subject: [PATCH] Meta tweaks --- .travis.yml | 2 +- Defaults.xcodeproj/project.pbxproj | 2 +- Sources/Defaults/Defaults.swift | 95 +++++++++++----------- Sources/Defaults/Observation+Combine.swift | 60 +++++++------- Sources/Defaults/Observation.swift | 88 ++++++++++---------- Tests/DefaultsTests/DefaultsTests.swift | 10 +-- readme.md | 4 +- 7 files changed, 134 insertions(+), 127 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f6646c..d728b5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: swift -osx_image: xcode11.2 +osx_image: xcode11.3 script: xcodebuild test -project Defaults.xcodeproj -scheme Defaults-macOS diff --git a/Defaults.xcodeproj/project.pbxproj b/Defaults.xcodeproj/project.pbxproj index 245f27f..df8106e 100644 --- a/Defaults.xcodeproj/project.pbxproj +++ b/Defaults.xcodeproj/project.pbxproj @@ -68,7 +68,7 @@ AD2FAA281CD0B6E100659CF4 /* DefaultsTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DefaultsTests.plist; sourceTree = ""; }; 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 = ""; }; + E286D0C623B8D51100570D1E /* Observation+Combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "Observation+Combine.swift"; sourceTree = ""; usesTabs = 1; }; E3EB3E32216505920033B089 /* util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = util.swift; sourceTree = ""; usesTabs = 1; }; E3EB3E34216507AE0033B089 /* Observation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Observation.swift; sourceTree = ""; usesTabs = 1; }; /* End PBXFileReference section */ diff --git a/Sources/Defaults/Defaults.swift b/Sources/Defaults/Defaults.swift index f252955..0d41884 100644 --- a/Sources/Defaults/Defaults.swift +++ b/Sources/Defaults/Defaults.swift @@ -16,13 +16,13 @@ public final class Defaults { fileprivate init() {} } - public final class Key: Keys { + public final class Key: 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: Keys { + public final class NSSecureCodingKey: 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: Keys { + public final class OptionalKey: 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: Keys { + public final class NSSecureCodingOptionalKey: 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(key: Key) -> T { + public static subscript(key: Key) -> 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(key: NSSecureCodingKey) -> T { + public static subscript(key: NSSecureCodingKey) -> 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(key: OptionalKey) -> T? { + public static subscript(key: OptionalKey) -> 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(key: NSSecureCodingOptionalKey) -> T? { + public static subscript(key: NSSecureCodingOptionalKey) -> Value? { get { key.suite[key] } set { key.suite[key] = newValue @@ -140,7 +140,7 @@ public final class Defaults { //=> false ``` */ - public static func reset(_ keys: Key..., suite: UserDefaults = .standard) { + public static func reset(_ keys: Key..., 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(_ keys: NSSecureCodingKey..., suite: UserDefaults = .standard) { + public static func reset(_ keys: NSSecureCodingKey..., suite: UserDefaults = .standard) { reset(keys, suite: suite) } @@ -175,7 +175,7 @@ public final class Defaults { //=> false ``` */ - public static func reset(_ keys: [Key], suite: UserDefaults = .standard) { + public static func reset(_ keys: [Key], 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(_ keys: [NSSecureCodingKey], suite: UserDefaults = .standard) { + public static func reset(_ keys: [NSSecureCodingKey], 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(_ keys: OptionalKey..., suite: UserDefaults = .standard) { + public static func reset(_ keys: OptionalKey..., 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(_ keys: NSSecureCodingOptionalKey..., suite: UserDefaults = .standard) { + public static func reset(_ keys: NSSecureCodingOptionalKey..., suite: UserDefaults = .standard) { reset(keys, suite: suite) } @@ -248,7 +248,7 @@ public final class Defaults { //=> nil ``` */ - public static func reset(_ keys: [OptionalKey], suite: UserDefaults = .standard) { + public static func reset(_ keys: [OptionalKey], 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(_ keys: [NSSecureCodingOptionalKey], suite: UserDefaults = .standard) { + public static func reset(_ keys: [NSSecureCodingOptionalKey], suite: UserDefaults = .standard) { for key in keys { key.suite[key] = nil } @@ -278,9 +278,9 @@ public final class Defaults { } extension UserDefaults { - private func _get(_ key: String) -> T? { - if UserDefaults.isNativelySupportedType(T.self) { - return object(forKey: key) as? T + private func _get(_ 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(_ key: String) -> T? { - if UserDefaults.isNativelySupportedType(T.self) { - return object(forKey: key) as? T + private func _get(_ 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(_ value: T) -> String? { + fileprivate func _encode(_ 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(_ key: String, to value: T) { - if UserDefaults.isNativelySupportedType(T.self) { + private func _set(_ 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(_ key: String, to value: T) { - if UserDefaults.isNativelySupportedType(T.self) { + private func _set(_ 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(key: Defaults.Key) -> T { + public subscript(key: Defaults.Key) -> 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(key: Defaults.NSSecureCodingKey) -> T { + public subscript(key: Defaults.NSSecureCodingKey) -> Value { get { _get(key.name) ?? key.defaultValue } set { _set(key.name, to: newValue) } } - public subscript(key: Defaults.OptionalKey) -> T? { + public subscript(key: Defaults.OptionalKey) -> 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(key: Defaults.NSSecureCodingOptionalKey) -> T? { + public subscript(key: Defaults.NSSecureCodingOptionalKey) -> Value? { get { _get(key.name) } set { guard let value = newValue else { @@ -392,15 +392,16 @@ extension UserDefaults { } } - fileprivate static func isNativelySupportedType(_ type: T.Type) -> Bool { + fileprivate static func isNativelySupportedType(_ 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 diff --git a/Sources/Defaults/Observation+Combine.swift b/Sources/Defaults/Observation+Combine.swift index fceed78..6cac36f 100644 --- a/Sources/Defaults/Observation+Combine.swift +++ b/Sources/Defaults/Observation+Combine.swift @@ -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( - _ key: Defaults.Key, + public static func publisher( + _ key: Defaults.Key, options: NSKeyValueObservingOptions = [.initial, .old, .new] - ) -> AnyPublisher, Never> { + ) -> AnyPublisher, Never> { let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options) - .map { KeyChange(change: $0, defaultValue: key.defaultValue) } + .map { KeyChange(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( - _ key: Defaults.NSSecureCodingKey, + public static func publisher( + _ key: Defaults.NSSecureCodingKey, options: NSKeyValueObservingOptions = [.initial, .old, .new] - ) -> AnyPublisher, Never> { + ) -> AnyPublisher, Never> { let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options) - .map { NSSecureCodingKeyChange(change: $0, defaultValue: key.defaultValue) } + .map { NSSecureCodingKeyChange(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( - _ key: Defaults.OptionalKey, + public static func publisher( + _ key: Defaults.OptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new] - ) -> AnyPublisher, Never> { + ) -> AnyPublisher, Never> { let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options) - .map { OptionalKeyChange(change: $0) } + .map { OptionalKeyChange(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( - _ key: Defaults.NSSecureCodingOptionalKey, + public static func publisher( + _ key: Defaults.NSSecureCodingOptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new] - ) -> AnyPublisher, Never> { + ) -> AnyPublisher, Never> { let publisher = DefaultsPublisher(suite: key.suite, key: key.name, options: options) - .map { NSSecureCodingOptionalKeyChange(change: $0) } + .map { NSSecureCodingOptionalKeyChange(change: $0) } return AnyPublisher(publisher) } @@ -138,8 +140,8 @@ extension Defaults { Publisher for multiple `Key` 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( - keys: Defaults.Key..., + public static func publisher( + keys: Defaults.Key..., options: NSKeyValueObservingOptions = [.initial, .old, .new] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -160,8 +162,8 @@ extension Defaults { Publisher for multiple `OptionalKey` 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( - keys: Defaults.OptionalKey..., + public static func publisher( + keys: Defaults.OptionalKey..., options: NSKeyValueObservingOptions = [.initial, .old, .new] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -182,8 +184,8 @@ extension Defaults { Publisher for multiple `NSSecureCodingKey` 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( - keys: Defaults.NSSecureCodingKey..., + public static func publisher( + keys: Defaults.NSSecureCodingKey..., options: NSKeyValueObservingOptions = [.initial, .old, .new] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -204,8 +206,8 @@ extension Defaults { Publisher for multiple `NSSecureCodingOptionalKey` 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( - keys: Defaults.NSSecureCodingOptionalKey..., + public static func publisher( + keys: Defaults.NSSecureCodingOptionalKey..., options: NSKeyValueObservingOptions = [.initial, .old, .new] ) -> AnyPublisher { let initial = Empty(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 diff --git a/Sources/Defaults/Observation.swift b/Sources/Defaults/Observation.swift index 8bbfb52..ec5b4c5 100644 --- a/Sources/Defaults/Observation.swift +++ b/Sources/Defaults/Observation.swift @@ -26,7 +26,7 @@ public protocol DefaultsObservation: AnyObject { } extension Defaults { - private static func deserialize(_ value: Any?, to type: T.Type) -> T? { + private static func deserialize(_ 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(_ value: Any?, to type: T.Type) -> T? { + private static func deserialize(_ 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 { + public struct KeyChange { 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 { + public struct NSSecureCodingKeyChange { 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 { + public struct OptionalKeyChange { 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 { + public struct NSSecureCodingOptionalKeyChange { 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( - _ key: Defaults.Key, + public static func observe( + _ key: Defaults.Key, options: NSKeyValueObservingOptions = [.initial, .old, .new], - handler: @escaping (KeyChange) -> Void + handler: @escaping (KeyChange) -> Void ) -> DefaultsObservation { let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in handler( - KeyChange(change: change, defaultValue: key.defaultValue) + KeyChange(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( - _ key: Defaults.NSSecureCodingKey, + public static func observe( + _ key: Defaults.NSSecureCodingKey, options: NSKeyValueObservingOptions = [.initial, .old, .new], - handler: @escaping (NSSecureCodingKeyChange) -> Void + handler: @escaping (NSSecureCodingKeyChange) -> Void ) -> DefaultsObservation { let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in handler( - NSSecureCodingKeyChange(change: change, defaultValue: key.defaultValue) + NSSecureCodingKeyChange(change: change, defaultValue: key.defaultValue) ) } observation.start(options: options) @@ -269,14 +269,14 @@ extension Defaults { } ``` */ - public static func observe( - _ key: Defaults.OptionalKey, + public static func observe( + _ key: Defaults.OptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new], - handler: @escaping (OptionalKeyChange) -> Void + handler: @escaping (OptionalKeyChange) -> Void ) -> DefaultsObservation { let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in handler( - OptionalKeyChange(change: change) + OptionalKeyChange(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( - _ key: Defaults.NSSecureCodingOptionalKey, + public static func observe( + _ key: Defaults.NSSecureCodingOptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new], - handler: @escaping (NSSecureCodingOptionalKeyChange) -> Void + handler: @escaping (NSSecureCodingOptionalKeyChange) -> Void ) -> DefaultsObservation { let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in handler( - NSSecureCodingOptionalKeyChange(change: change) + NSSecureCodingOptionalKeyChange(change: change) ) } observation.start(options: options) diff --git a/Tests/DefaultsTests/DefaultsTests.swift b/Tests/DefaultsTests/DefaultsTests.swift index 0fce6d0..059a652 100644 --- a/Tests/DefaultsTests/DefaultsTests.swift +++ b/Tests/DefaultsTests/DefaultsTests.swift @@ -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" diff --git a/readme.md b/readme.md index 903b1fc..5b91a94 100644 --- a/readme.md +++ b/readme.md @@ -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 ``` -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.