diff --git a/Defaults.xcodeproj/project.pbxproj b/Defaults.xcodeproj/project.pbxproj index 0c7dfe4..83c6f85 100644 --- a/Defaults.xcodeproj/project.pbxproj +++ b/Defaults.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 52D6D9871BEFF229002C0205 /* Defaults.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* Defaults.framework */; }; + 6614F6E322FC6E1C00B0C9CE /* readme.md in Resources */ = {isa = PBXBuildFile; fileRef = 6614F6E222FC6E1C00B0C9CE /* readme.md */; }; 8933C7851EB5B820000D00A4 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* Defaults.swift */; }; 8933C7861EB5B820000D00A4 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* Defaults.swift */; }; 8933C7871EB5B820000D00A4 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* Defaults.swift */; }; @@ -57,6 +58,7 @@ 52D6D9E21BEFFF6E002C0205 /* Defaults.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Defaults.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52D6D9F01BEFFFBE002C0205 /* Defaults.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Defaults.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52D6DA0F1BF000BD002C0205 /* Defaults.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Defaults.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6614F6E222FC6E1C00B0C9CE /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 8933C7841EB5B820000D00A4 /* Defaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Defaults.swift; sourceTree = ""; usesTabs = 1; }; 8933C7891EB5B82A000D00A4 /* DefaultsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DefaultsTests.swift; sourceTree = ""; usesTabs = 1; }; AD2FAA261CD0B6D800659CF4 /* Defaults.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Defaults.plist; sourceTree = ""; }; @@ -126,6 +128,7 @@ 52D6D9721BEFF229002C0205 = { isa = PBXGroup; children = ( + 6614F6E222FC6E1C00B0C9CE /* readme.md */, 8933C7811EB5B7E0000D00A4 /* Sources */, 8933C7831EB5B7EB000D00A4 /* Tests */, 52D6D99C1BEFF38C002C0205 /* Configs */, @@ -457,6 +460,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6614F6E322FC6E1C00B0C9CE /* readme.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/Defaults/Defaults.swift b/Sources/Defaults/Defaults.swift index f897dfa..8dbf3fc 100644 --- a/Sources/Defaults/Defaults.swift +++ b/Sources/Defaults/Defaults.swift @@ -65,6 +65,38 @@ public final class Defaults { suite.removeObject(forKey: key) } } + + /// Reset keys back to their default values. + /// - Parameter keys: Keys to reset. + /// - Parameter suite: `UserDefaults` suite. + public func reset(_ keys: Defaults.Key..., suite: UserDefaults = .standard) { + reset(keys, suite: suite) + } + + /// Reset an array of keys back to their default values. + /// - Parameter keys: Keys to reset. + /// - Parameter suite: `UserDefaults` suite. + public func reset(_ keys: [Defaults.Key], suite: UserDefaults = .standard) { + for key in keys { + key.suite[key] = key.defaultValue + } + } + + /// Reset optional keys back to `nil`. + /// - Parameter keys: Keys to reset. + /// - Parameter suite: `UserDefaults` suite. + public func reset(_ keys: Defaults.OptionalKey..., suite: UserDefaults = .standard) { + reset(keys, suite: suite) + } + + /// Reset an array of optional keys back to `nil`. + /// - Parameter keys: Keys to reset. + /// - Parameter suite: `UserDefaults` suite. + public func reset(_ keys: [Defaults.OptionalKey], suite: UserDefaults = .standard) { + for key in keys { + key.suite[key] = nil + } + } } // Has to be `defaults` lowercase until Swift supports static subscripts… diff --git a/Tests/DefaultsTests/DefaultsTests.swift b/Tests/DefaultsTests/DefaultsTests.swift index 3ee1439..9ca912e 100644 --- a/Tests/DefaultsTests/DefaultsTests.swift +++ b/Tests/DefaultsTests/DefaultsTests.swift @@ -191,4 +191,65 @@ final class DefaultsTests: XCTestCase { waitForExpectations(timeout: 10) } + + func testResetKey() { + let defaultString1 = "foo1" + let defaultString2 = "foo2" + let newString1 = "bar1" + let newString2 = "bar2" + let key1 = Defaults.Key("key1", default: defaultString1) + let key2 = Defaults.Key("key2", default: defaultString2) + defaults[key1] = newString1 + defaults[key2] = newString2 + defaults.reset(key1) + XCTAssertEqual(defaults[key1], defaultString1) + XCTAssertEqual(defaults[key2], newString2) + } + + 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 + defaults.reset(key1, key2) + XCTAssertEqual(defaults[key1], defaultString1) + XCTAssertEqual(defaults[key2], defaultString2) + XCTAssertEqual(defaults[key3], newString3) + } + + func testResetOptionalKey() { + let newString1 = "bar1" + let newString2 = "bar2" + let key1 = Defaults.OptionalKey("optionalKey1") + let key2 = Defaults.OptionalKey("optionalKey2") + defaults[key1] = newString1 + defaults[key2] = newString2 + defaults.reset(key1) + XCTAssertEqual(defaults[key1], nil) + XCTAssertEqual(defaults[key2], newString2) + } + + func testResetOptionalKeyArray() { + let newString1 = "bar1" + let newString2 = "bar2" + let newString3 = "bar3" + let key1 = Defaults.OptionalKey("aoptionalKey1") + let key2 = Defaults.OptionalKey("aoptionalKey2") + let key3 = Defaults.OptionalKey("aoptionalKey3") + defaults[key1] = newString1 + defaults[key2] = newString2 + defaults[key3] = newString3 + defaults.reset(key1, key2) + XCTAssertEqual(defaults[key1], nil) + XCTAssertEqual(defaults[key2], nil) + XCTAssertEqual(defaults[key3], newString3) + } } diff --git a/readme.md b/readme.md index 08fb376..e4931d8 100644 --- a/readme.md +++ b/readme.md @@ -173,6 +173,24 @@ defaults[.isUnicornMode] = true In contrast to the native `UserDefaults` key observation, here you receive a strongly-typed change object. +### Reset keys to their default values + +```swift +extension Defaults.Keys { + static let isUnicornMode = Key("isUnicornMode", default: false) +} + +defaults[.isUnicornMode] = true +//=> true + +defaults.reset(.isUnicornMode) + +defaults[.isUnicornMode] +//=> false +``` + +This works for `OptionalKey` too, which will be reset back to `nil`. + ### Default values are registered with UserDefaults When you create a `Defaults.Key`, it automatically registers the `default` value with normal UserDefaults. This means you can make use of the default value in, for example, bindings in Interface Builder.