From 15c096d7fd7e7ef0ad4e4824cb3f96bad941440f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 17 Apr 2020 22:32:44 +0800 Subject: [PATCH] Fix `Defaults.reset()` --- Defaults.xcodeproj/project.pbxproj | 20 + .../xcschemes/Defaults-macOS.xcscheme | 34 +- Sources/Defaults/Defaults.swift | 256 +--- Sources/Defaults/Observation+Combine.swift | 6 +- Sources/Defaults/Observation.swift | 6 +- Sources/Defaults/Reset.swift | 1094 +++++++++++++++++ Sources/Defaults/UserDefaults.swift | 134 ++ Tests/DefaultsTests/DefaultsTests.swift | 80 +- readme.md | 18 +- 9 files changed, 1335 insertions(+), 313 deletions(-) create mode 100644 Sources/Defaults/Reset.swift create mode 100644 Sources/Defaults/UserDefaults.swift diff --git a/Defaults.xcodeproj/project.pbxproj b/Defaults.xcodeproj/project.pbxproj index df8106e..a6e8e0c 100644 --- a/Defaults.xcodeproj/project.pbxproj +++ b/Defaults.xcodeproj/project.pbxproj @@ -21,6 +21,14 @@ E286D0C823B8D54C00570D1E /* Observation+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286D0C623B8D51100570D1E /* Observation+Combine.swift */; }; E286D0C923B8D54D00570D1E /* Observation+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286D0C623B8D51100570D1E /* Observation+Combine.swift */; }; E286D0CA23B8D54E00570D1E /* Observation+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = E286D0C623B8D51100570D1E /* Observation+Combine.swift */; }; + E339B3B32449ED2000E7A40A /* Reset.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B22449ED2000E7A40A /* Reset.swift */; }; + E339B3B42449ED2000E7A40A /* Reset.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B22449ED2000E7A40A /* Reset.swift */; }; + E339B3B52449ED2000E7A40A /* Reset.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B22449ED2000E7A40A /* Reset.swift */; }; + E339B3B62449ED2000E7A40A /* Reset.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B22449ED2000E7A40A /* Reset.swift */; }; + E339B3B82449F10D00E7A40A /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B72449F10D00E7A40A /* UserDefaults.swift */; }; + E339B3B92449F10D00E7A40A /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B72449F10D00E7A40A /* UserDefaults.swift */; }; + E339B3BA2449F10D00E7A40A /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B72449F10D00E7A40A /* UserDefaults.swift */; }; + E339B3BB2449F10D00E7A40A /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = E339B3B72449F10D00E7A40A /* UserDefaults.swift */; }; E3EB3E33216505920033B089 /* util.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3EB3E32216505920033B089 /* util.swift */; }; E3EB3E35216507AE0033B089 /* Observation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3EB3E34216507AE0033B089 /* Observation.swift */; }; E3EB3E36216507B50033B089 /* Observation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3EB3E34216507AE0033B089 /* Observation.swift */; }; @@ -69,6 +77,8 @@ 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; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "Observation+Combine.swift"; sourceTree = ""; usesTabs = 1; }; + E339B3B22449ED2000E7A40A /* Reset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Reset.swift; sourceTree = ""; usesTabs = 1; }; + E339B3B72449F10D00E7A40A /* UserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserDefaults.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 */ @@ -201,6 +211,8 @@ isa = PBXGroup; children = ( 8933C7841EB5B820000D00A4 /* Defaults.swift */, + E339B3B72449F10D00E7A40A /* UserDefaults.swift */, + E339B3B22449ED2000E7A40A /* Reset.swift */, E3EB3E34216507AE0033B089 /* Observation.swift */, E286D0C623B8D51100570D1E /* Observation+Combine.swift */, E3EB3E32216505920033B089 /* util.swift */, @@ -491,8 +503,10 @@ files = ( E286D0C823B8D54C00570D1E /* Observation+Combine.swift in Sources */, 8933C7851EB5B820000D00A4 /* Defaults.swift in Sources */, + E339B3B92449F10D00E7A40A /* UserDefaults.swift in Sources */, E3EB3E35216507AE0033B089 /* Observation.swift in Sources */, E3EB3E33216505920033B089 /* util.swift in Sources */, + E339B3B42449ED2000E7A40A /* Reset.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -510,8 +524,10 @@ files = ( E286D0CA23B8D54E00570D1E /* Observation+Combine.swift in Sources */, E3EB3E3A216507C40033B089 /* util.swift in Sources */, + E339B3BB2449F10D00E7A40A /* UserDefaults.swift in Sources */, E3EB3E37216507B50033B089 /* Observation.swift in Sources */, 8933C7871EB5B820000D00A4 /* Defaults.swift in Sources */, + E339B3B62449ED2000E7A40A /* Reset.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -521,8 +537,10 @@ files = ( E286D0C923B8D54D00570D1E /* Observation+Combine.swift in Sources */, E3EB3E3B216507C40033B089 /* util.swift in Sources */, + E339B3BA2449F10D00E7A40A /* UserDefaults.swift in Sources */, E3EB3E38216507B60033B089 /* Observation.swift in Sources */, 8933C7881EB5B820000D00A4 /* Defaults.swift in Sources */, + E339B3B52449ED2000E7A40A /* Reset.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -532,8 +550,10 @@ files = ( E286D0C723B8D51100570D1E /* Observation+Combine.swift in Sources */, E3EB3E39216507C30033B089 /* util.swift in Sources */, + E339B3B82449F10D00E7A40A /* UserDefaults.swift in Sources */, E3EB3E36216507B50033B089 /* Observation.swift in Sources */, 8933C7861EB5B820000D00A4 /* Defaults.swift in Sources */, + E339B3B32449ED2000E7A40A /* Reset.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Defaults.xcodeproj/xcshareddata/xcschemes/Defaults-macOS.xcscheme b/Defaults.xcodeproj/xcshareddata/xcschemes/Defaults-macOS.xcscheme index 6c18a07..336b829 100644 --- a/Defaults.xcodeproj/xcshareddata/xcschemes/Defaults-macOS.xcscheme +++ b/Defaults.xcodeproj/xcshareddata/xcschemes/Defaults-macOS.xcscheme @@ -26,20 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - - + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> - - + + + + + + - - : Keys { + public final class Key: Keys, _DefaultsBaseKey { public let name: String public let defaultValue: Value public let suite: UserDefaults @@ -41,7 +53,7 @@ public enum 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, _DefaultsBaseKey { public let name: String public let defaultValue: Value public let suite: UserDefaults @@ -68,7 +80,7 @@ public enum 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, _DefaultsBaseKey { public let name: String public let suite: UserDefaults @@ -104,108 +116,11 @@ public enum Defaults { key.suite[key] = newValue } } - +} + +extension Defaults { /** - Reset the given keys back to their default values. - - - Parameter keys: Keys to reset. - - Parameter suite: `UserDefaults` suite. - - ``` - extension Defaults.Keys { - static let isUnicornMode = Key("isUnicornMode", default: false) - } - - Defaults[.isUnicornMode] = true - //=> true - - Defaults.reset(.isUnicornMode) - - Defaults[.isUnicornMode] - //=> false - ``` - */ - public static func reset(_ keys: Key..., suite: UserDefaults = .standard) { - reset(keys, suite: suite) - } - - /** - Reset the given keys back to their default values. - - - Parameter keys: Keys to reset. - - 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) { - reset(keys, suite: suite) - } - - /** - Reset the given array of keys back to their default values. - - - Parameter keys: Keys to reset. - - Parameter suite: `UserDefaults` suite. - - ``` - extension Defaults.Keys { - static let isUnicornMode = Key("isUnicornMode", default: false) - } - - Defaults[.isUnicornMode] = true - //=> true - - Defaults.reset(.isUnicornMode) - - Defaults[.isUnicornMode] - //=> false - ``` - */ - public static func reset(_ keys: [Key], suite: UserDefaults = .standard) { - for key in keys { - key.suite[key] = key.defaultValue - } - } - - /** - Reset the given array of keys back to their default values. - - - Parameter keys: Keys to reset. - - 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) { - for key in keys { - key.suite[key] = key.defaultValue - } - } - - /** - Reset the given optional keys back to `nil`. - - - Parameter keys: Keys to reset. - - 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) { - reset(keys, suite: suite) - } - - /** - Reset the given array of optional keys back to `nil`. - - - Parameter keys: Keys to reset. - - 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) { - for key in keys { - key.suite[key] = nil - } - } - - /** - Remove all entries from the `UserDefaults` suite. + Remove all entries from the given `UserDefaults` suite. */ public static func removeAll(suite: UserDefaults = .standard) { for key in suite.dictionaryRepresentation().keys { @@ -226,136 +141,3 @@ extension Defaults.NSSecureCodingKey where Value: _DefaultsOptionalType { self.init(key, default: nil, suite: suite) } } - -extension UserDefaults { - private func _get(_ key: String) -> Value? { - if UserDefaults.isNativelySupportedType(Value.self) { - return object(forKey: key) as? Value - } - - guard - let text = string(forKey: key), - let data = "[\(text)]".data(using: .utf8) - else { - return nil - } - - do { - return (try JSONDecoder().decode([Value].self, from: data)).first - } catch { - print(error) - } - - return nil - } - - @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) -> Value? { - if UserDefaults.isNativelySupportedType(Value.self) { - return object(forKey: key) as? Value - } - - guard - let data = data(forKey: key) - else { - return nil - } - - do { - return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Value - } catch { - print(error) - } - - return nil - } - - 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 - // We need this: https://forums.swift.org/t/allowing-top-level-fragments-in-jsondecoder/11750 - let data = try JSONEncoder().encode([value]) - return String(String(data: data, encoding: .utf8)!.dropFirst().dropLast()) - } catch { - print(error) - return nil - } - } - - private func _set(_ key: String, to value: Value) { - if (value as? _DefaultsOptionalType)?.isNil == true { - removeObject(forKey: key) - return - } - - if UserDefaults.isNativelySupportedType(Value.self) { - set(value, forKey: key) - return - } - - set(_encode(value), forKey: 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, *) - private func _set(_ key: String, to value: Value) { - // TODO: Handle nil here too. - if UserDefaults.isNativelySupportedType(Value.self) { - set(value, forKey: key) - return - } - - set(try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true), forKey: key) - } - - public subscript(key: Defaults.Key) -> Value { - get { _get(key.name) ?? key.defaultValue } - set { - _set(key.name, to: newValue) - } - } - - @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) -> Value { - get { _get(key.name) ?? key.defaultValue } - set { - _set(key.name, to: newValue) - } - } - - @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) -> Value? { - get { _get(key.name) } - set { - guard let value = newValue else { - set(nil, forKey: key.name) - return - } - - _set(key.name, to: value) - } - } - - fileprivate static func isNativelySupportedType(_ type: T.Type) -> Bool { - switch type { - case - is Bool.Type, - is Bool?.Type, // swiftlint:disable:this discouraged_optional_boolean - is String.Type, - is String?.Type, - is Int.Type, - is Int?.Type, - is Double.Type, - is Double?.Type, - is Float.Type, - is Float?.Type, - is Date.Type, - is Date?.Type, - is Data.Type, - is Data?.Type: - return true - default: - return false - } - } -} diff --git a/Sources/Defaults/Observation+Combine.swift b/Sources/Defaults/Observation+Combine.swift index 2cd1307..c889ef4 100644 --- a/Sources/Defaults/Observation+Combine.swift +++ b/Sources/Defaults/Observation+Combine.swift @@ -133,7 +133,7 @@ extension Defaults { */ @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, iOSApplicationExtension 13.0, macOSApplicationExtension 10.15, tvOSApplicationExtension 13.0, watchOSApplicationExtension 6.0, *) public static func publisher( - keys:Key..., + keys: Key..., options: ObservationOptions = [.initial] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -155,7 +155,7 @@ extension Defaults { */ @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, iOSApplicationExtension 13.0, macOSApplicationExtension 10.15, tvOSApplicationExtension 13.0, watchOSApplicationExtension 6.0, *) public static func publisher( - keys: Defaults.NSSecureCodingKey..., + keys: NSSecureCodingKey..., options: ObservationOptions = [.initial] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -177,7 +177,7 @@ extension Defaults { */ @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, iOSApplicationExtension 13.0, macOSApplicationExtension 10.15, tvOSApplicationExtension 13.0, watchOSApplicationExtension 6.0, *) public static func publisher( - keys: Defaults.NSSecureCodingOptionalKey..., + keys: NSSecureCodingOptionalKey..., options: ObservationOptions = [.initial] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() diff --git a/Sources/Defaults/Observation.swift b/Sources/Defaults/Observation.swift index b77a483..5abd144 100644 --- a/Sources/Defaults/Observation.swift +++ b/Sources/Defaults/Observation.swift @@ -226,7 +226,7 @@ extension Defaults { ) -> Observation { 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) @@ -244,7 +244,7 @@ extension Defaults { ) -> Observation { 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) @@ -262,7 +262,7 @@ extension Defaults { ) -> Observation { 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/Sources/Defaults/Reset.swift b/Sources/Defaults/Reset.swift new file mode 100644 index 0000000..b0f3090 --- /dev/null +++ b/Sources/Defaults/Reset.swift @@ -0,0 +1,1094 @@ +import Foundation + +/* +TODO: When Swift gets support for static key paths, all of this could be simplified to just: + +``` +extension Defaults { + public static func reset(_ keys: KeyPath...) { + for key in keys { + Keys[keyPath: key].reset() + } + } +} +``` +*/ + +extension Defaults { + /** + Reset the given string keys back to their default values. + + Prefer using the strongly-typed keys instead whenever possible. This method can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic. + + - Parameter keys: String keys to reset. + - Parameter suite: `UserDefaults` suite. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(Defaults.Keys.isUnicornMode.name) + // Or `Defaults.reset("isUnicornMode")` + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset(_ keys: String..., suite: UserDefaults = .standard) { + reset(keys, suite: suite) + } + + /** + Reset the given string keys back to their default values. + + Prefer using the strongly-typed keys instead whenever possible. This method can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic. + + - Parameter keys: String keys to reset. + - Parameter suite: `UserDefaults` suite. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset([Defaults.Keys.isUnicornMode.name]) + // Or `Defaults.reset(["isUnicornMode"])` + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset(_ keys: [String], suite: UserDefaults = .standard) { + for key in keys { + suite.removeObject(forKey: key) + } + } +} + +extension Defaults { + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable + >( + _ key1: Key + ) { + key1.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable + >( + _ key1: Key, + _ key2: Key + ) { + key1.reset() + key2.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key + ) { + key1.reset() + key2.reset() + key3.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable, + Value6: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key, + _ key6: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable, + Value6: Codable, + Value7: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key, + _ key6: Key, + _ key7: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable, + Value6: Codable, + Value7: Codable, + Value8: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key, + _ key6: Key, + _ key7: Key, + _ key8: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable, + Value6: Codable, + Value7: Codable, + Value8: Codable, + Value9: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key, + _ key6: Key, + _ key7: Key, + _ key8: Key, + _ key9: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + + ``` + extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) + } + + Defaults[.isUnicornMode] = true + //=> true + + Defaults.reset(.isUnicornMode) + + Defaults[.isUnicornMode] + //=> false + ``` + */ + public static func reset< + Value1: Codable, + Value2: Codable, + Value3: Codable, + Value4: Codable, + Value5: Codable, + Value6: Codable, + Value7: Codable, + Value8: Codable, + Value9: Codable, + Value10: Codable + >( + _ key1: Key, + _ key2: Key, + _ key3: Key, + _ key4: Key, + _ key5: Key, + _ key6: Key, + _ key7: Key, + _ key8: Key, + _ key9: Key, + _ key10: Key + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + key10.reset() + } +} + +extension Defaults { + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding + >( + _ key1: NSSecureCodingKey + ) { + key1.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey, + _ key6: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey, + _ key6: NSSecureCodingKey, + _ key7: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey, + _ key6: NSSecureCodingKey, + _ key7: NSSecureCodingKey, + _ key8: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding, + Value9: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey, + _ key6: NSSecureCodingKey, + _ key7: NSSecureCodingKey, + _ key8: NSSecureCodingKey, + _ key9: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding, + Value9: NSSecureCoding, + Value10: NSSecureCoding + >( + _ key1: NSSecureCodingKey, + _ key2: NSSecureCodingKey, + _ key3: NSSecureCodingKey, + _ key4: NSSecureCodingKey, + _ key5: NSSecureCodingKey, + _ key6: NSSecureCodingKey, + _ key7: NSSecureCodingKey, + _ key8: NSSecureCodingKey, + _ key9: NSSecureCodingKey, + _ key10: NSSecureCodingKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + key10.reset() + } +} + +extension Defaults { + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey + ) { + key1.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey, + _ key6: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey, + _ key6: NSSecureCodingOptionalKey, + _ key7: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey, + _ key6: NSSecureCodingOptionalKey, + _ key7: NSSecureCodingOptionalKey, + _ key8: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding, + Value9: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey, + _ key6: NSSecureCodingOptionalKey, + _ key7: NSSecureCodingOptionalKey, + _ key8: NSSecureCodingOptionalKey, + _ key9: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + } + + /** + Reset the given keys back to their default values. + + You can specify up to 10 keys. If you need to specify more, call this method multiple times. + + The 10 limit is a Swift generics limitation. If you really want, you could specify more overloads. + */ + @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< + Value1: NSSecureCoding, + Value2: NSSecureCoding, + Value3: NSSecureCoding, + Value4: NSSecureCoding, + Value5: NSSecureCoding, + Value6: NSSecureCoding, + Value7: NSSecureCoding, + Value8: NSSecureCoding, + Value9: NSSecureCoding, + Value10: NSSecureCoding + >( + _ key1: NSSecureCodingOptionalKey, + _ key2: NSSecureCodingOptionalKey, + _ key3: NSSecureCodingOptionalKey, + _ key4: NSSecureCodingOptionalKey, + _ key5: NSSecureCodingOptionalKey, + _ key6: NSSecureCodingOptionalKey, + _ key7: NSSecureCodingOptionalKey, + _ key8: NSSecureCodingOptionalKey, + _ key9: NSSecureCodingOptionalKey, + _ key10: NSSecureCodingOptionalKey + ) { + key1.reset() + key2.reset() + key3.reset() + key4.reset() + key5.reset() + key6.reset() + key7.reset() + key8.reset() + key9.reset() + key10.reset() + } +} diff --git a/Sources/Defaults/UserDefaults.swift b/Sources/Defaults/UserDefaults.swift new file mode 100644 index 0000000..e9d70d1 --- /dev/null +++ b/Sources/Defaults/UserDefaults.swift @@ -0,0 +1,134 @@ +import Foundation + +extension UserDefaults { + private func _get(_ key: String) -> Value? { + if UserDefaults.isNativelySupportedType(Value.self) { + return object(forKey: key) as? Value + } + + guard + let text = string(forKey: key), + let data = "[\(text)]".data(using: .utf8) + else { + return nil + } + + do { + return (try JSONDecoder().decode([Value].self, from: data)).first + } catch { + print(error) + } + + return nil + } + + @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) -> Value? { + if UserDefaults.isNativelySupportedType(Value.self) { + return object(forKey: key) as? Value + } + + guard + let data = data(forKey: key) + else { + return nil + } + + do { + return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Value + } catch { + print(error) + } + + return nil + } + + 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 + // We need this: https://forums.swift.org/t/allowing-top-level-fragments-in-jsondecoder/11750 + let data = try JSONEncoder().encode([value]) + return String(String(data: data, encoding: .utf8)!.dropFirst().dropLast()) + } catch { + print(error) + return nil + } + } + + private func _set(_ key: String, to value: Value) { + if (value as? _DefaultsOptionalType)?.isNil == true { + removeObject(forKey: key) + return + } + + if UserDefaults.isNativelySupportedType(Value.self) { + set(value, forKey: key) + return + } + + set(_encode(value), forKey: 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, *) + private func _set(_ key: String, to value: Value) { + // TODO: Handle nil here too. + if UserDefaults.isNativelySupportedType(Value.self) { + set(value, forKey: key) + return + } + + set(try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true), forKey: key) + } + + public subscript(key: Defaults.Key) -> Value { + get { _get(key.name) ?? key.defaultValue } + set { + _set(key.name, to: newValue) + } + } + + @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) -> Value { + get { _get(key.name) ?? key.defaultValue } + set { + _set(key.name, to: newValue) + } + } + + @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) -> Value? { + get { _get(key.name) } + set { + guard let value = newValue else { + set(nil, forKey: key.name) + return + } + + _set(key.name, to: value) + } + } + + static func isNativelySupportedType(_ type: T.Type) -> Bool { + switch type { + case + is Bool.Type, + is Bool?.Type, // swiftlint:disable:this discouraged_optional_boolean + is String.Type, + is String?.Type, + is Int.Type, + is Int?.Type, + is Double.Type, + is Double?.Type, + is Float.Type, + is Float?.Type, + is Date.Type, + is Date?.Type, + is Data.Type, + is Data?.Type: + return true + default: + return false + } + } +} diff --git a/Tests/DefaultsTests/DefaultsTests.swift b/Tests/DefaultsTests/DefaultsTests.swift index 52813f4..e6d2906 100644 --- a/Tests/DefaultsTests/DefaultsTests.swift +++ b/Tests/DefaultsTests/DefaultsTests.swift @@ -509,46 +509,46 @@ final class DefaultsTests: XCTestCase { } func testResetKey() { - let defaultString1 = "foo1" - let defaultString2 = "foo2" - let defaultString3 = "foo3" - let newString1 = "bar1" - let newString2 = "bar2" - let newString3 = "bar3" - let key1 = Defaults.Key("key1", default: defaultString1) - let key2 = Defaults.Key("key2", default: defaultString2) - Defaults[key1] = newString1 - Defaults[key2] = newString2 + let defaultFixture1 = "foo1" + let defaultFixture2 = 0 + let defaultFixture3 = "foo3" + let newFixture1 = "bar1" + let newFixture2 = 1 + let newFixture3 = "bar3" + let key1 = Defaults.Key("key1", default: defaultFixture1) + let key2 = Defaults.Key("key2", default: defaultFixture2) + Defaults[key1] = newFixture1 + Defaults[key2] = newFixture2 Defaults.reset(key1) - XCTAssertEqual(Defaults[key1], defaultString1) - XCTAssertEqual(Defaults[key2], newString2) + XCTAssertEqual(Defaults[key1], defaultFixture1) + XCTAssertEqual(Defaults[key2], newFixture2) if #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, *) { - let key3 = Defaults.NSSecureCodingKey("key3", default: ExamplePersistentHistory(value: defaultString3)) - Defaults[key3] = ExamplePersistentHistory(value: newString3) + let key3 = Defaults.NSSecureCodingKey("key3", default: ExamplePersistentHistory(value: defaultFixture3)) + Defaults[key3] = ExamplePersistentHistory(value: newFixture3) Defaults.reset(key3) - XCTAssertEqual(Defaults[key3].value, defaultString3) + XCTAssertEqual(Defaults[key3].value, defaultFixture3) } } - func testResetKeyArray() { - let defaultString1 = "foo1" - let defaultString2 = "foo2" - let defaultString3 = "foo3" - let newString1 = "bar1" - let newString2 = "bar2" - let newString3 = "bar3" - let key1 = Defaults.Key("akey1", default: defaultString1) - let key2 = Defaults.Key("akey2", default: defaultString2) - let key3 = Defaults.Key("akey3", default: defaultString3) - Defaults[key1] = newString1 - Defaults[key2] = newString2 - Defaults[key3] = newString3 + func testResetMultipleKeys() { + let defaultFxiture1 = "foo1" + let defaultFixture2 = 0 + let defaultFixture3 = "foo3" + let newFixture1 = "bar1" + let newFixture2 = 1 + let newFixture3 = "bar3" + let key1 = Defaults.Key("akey1", default: defaultFxiture1) + let key2 = Defaults.Key("akey2", default: defaultFixture2) + let key3 = Defaults.Key("akey3", default: defaultFixture3) + Defaults[key1] = newFixture1 + Defaults[key2] = newFixture2 + Defaults[key3] = newFixture3 Defaults.reset(key1, key2) - XCTAssertEqual(Defaults[key1], defaultString1) - XCTAssertEqual(Defaults[key2], defaultString2) - XCTAssertEqual(Defaults[key3], newString3) + XCTAssertEqual(Defaults[key1], defaultFxiture1) + XCTAssertEqual(Defaults[key2], defaultFixture2) + XCTAssertEqual(Defaults[key3], newFixture3) } func testResetOptionalKey() { @@ -571,20 +571,20 @@ final class DefaultsTests: XCTestCase { } } - func testResetOptionalKeyArray() { - let newString1 = "bar1" - let newString2 = "bar2" - let newString3 = "bar3" + func testResetMultipleOptionalKeys() { + let newFixture1 = "bar1" + let newFixture2 = 1 + let newFixture3 = "bar3" let key1 = Defaults.Key("aoptionalKey1") - let key2 = Defaults.Key("aoptionalKey2") + let key2 = Defaults.Key("aoptionalKey2") let key3 = Defaults.Key("aoptionalKey3") - Defaults[key1] = newString1 - Defaults[key2] = newString2 - Defaults[key3] = newString3 + Defaults[key1] = newFixture1 + Defaults[key2] = newFixture2 + Defaults[key3] = newFixture3 Defaults.reset(key1, key2) XCTAssertEqual(Defaults[key1], nil) XCTAssertEqual(Defaults[key2], nil) - XCTAssertEqual(Defaults[key3], newString3) + XCTAssertEqual(Defaults[key3], newFixture3) } func testObserveWithLifetimeTie() { diff --git a/readme.md b/readme.md index dd35c49..529d6aa 100644 --- a/readme.md +++ b/readme.md @@ -318,22 +318,16 @@ Type: `class` Create a NSSecureCoding key with an optional value. -#### `Defaults.reset` - -```swift -Defaults.reset(_ keys: Defaults.Key..., suite: UserDefaults = .standard) -Defaults.reset(_ keys: [Defaults.Key], suite: UserDefaults = .standard) - -Defaults.reset(_ keys: Defaults.NSSecureCodingKey..., suite: UserDefaults = .standard) -Defaults.reset(_ keys: [Defaults.NSSecureCodingKey], suite: UserDefaults = .standard) -Defaults.reset(_ keys: Defaults.NSSecureCodingOptionalKey..., suite: UserDefaults = .standard) -Defaults.reset(_ keys: [Defaults.NSSecureCodingOptionalKey], suite: UserDefaults = .standard) -``` +#### `Defaults.reset(key, …)` Type: `func` Reset the given keys back to their default values. +You can specify up to 10 keys. If you need to specify more, call this method multiple times. + +You can also specify string keys, which can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic. + #### `Defaults.observe` ```swift @@ -444,7 +438,7 @@ Defaults.removeAll(suite: UserDefaults = .standard) Type: `func` -Remove all entries from the `UserDefaults` suite. +Remove all entries from the given `UserDefaults` suite. ### `Defaults.Observation`