From 90ac6f88021e22d58b109b71866bd21471b898fe Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 11 Sep 2019 11:59:28 +0700 Subject: [PATCH] Switch to static subscript on `Defaults` --- Defaults.podspec | 2 +- Defaults.xcodeproj/project.pbxproj | 22 +--- Sources/Defaults/Defaults.swift | 140 +++++++++++++++++------- Sources/Defaults/Observation.swift | 12 +- Tests/DefaultsTests/DefaultsTests.swift | 132 +++++++++++----------- readme.md | 59 ++++++---- 6 files changed, 213 insertions(+), 154 deletions(-) diff --git a/Defaults.podspec b/Defaults.podspec index 4c7f3d2..2a9f59b 100644 --- a/Defaults.podspec +++ b/Defaults.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.authors = { 'Sindre Sorhus' => 'sindresorhus@gmail.com' } s.source = { :git => 'https://github.com/sindresorhus/Defaults.git', :tag => "v#{s.version}" } s.source_files = 'Sources/**/*.swift' - s.swift_version = '5.0' + s.swift_version = '5.1' s.macos.deployment_target = '10.12' s.ios.deployment_target = '10.0' s.tvos.deployment_target = '10.0' diff --git a/Defaults.xcodeproj/project.pbxproj b/Defaults.xcodeproj/project.pbxproj index 83c6f85..124a801 100644 --- a/Defaults.xcodeproj/project.pbxproj +++ b/Defaults.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* 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 */; }; @@ -58,7 +57,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 = ""; }; + 6614F6E222FC6E1C00B0C9CE /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; lineEnding = 0; path = readme.md; sourceTree = ""; usesTabs = 1; }; 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 = ""; }; @@ -460,7 +459,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6614F6E322FC6E1C00B0C9CE /* readme.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -621,7 +619,7 @@ SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -674,7 +672,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -706,7 +704,6 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -733,7 +730,6 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; }; name = Release; }; @@ -754,7 +750,6 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -775,7 +770,6 @@ PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; }; name = Release; }; @@ -799,7 +793,6 @@ PRODUCT_NAME = Defaults; SDKROOT = watchos; SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 3.0; }; @@ -827,7 +820,6 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 3.0; }; @@ -853,7 +845,6 @@ PRODUCT_NAME = Defaults; SDKROOT = appletvos; SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 10.0; }; @@ -881,7 +872,6 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 10.0; }; @@ -910,7 +900,6 @@ PRODUCT_NAME = Defaults; SDKROOT = macosx; SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -939,7 +928,6 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; }; name = Release; }; @@ -957,7 +945,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.Defaults.Defaults-macOS-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -977,7 +964,6 @@ SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; }; name = Release; }; @@ -996,7 +982,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = appletvos; - SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 10.0; }; name = Debug; @@ -1018,7 +1003,6 @@ SDKROOT = appletvos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 10.0; }; name = Release; diff --git a/Sources/Defaults/Defaults.swift b/Sources/Defaults/Defaults.swift index 8dbf3fc..b4891a5 100644 --- a/Sources/Defaults/Defaults.swift +++ b/Sources/Defaults/Defaults.swift @@ -14,6 +14,7 @@ public final class Defaults { public let defaultValue: T public let suite: UserDefaults + /// Create a defaults key. public init(_ key: String, default defaultValue: T, suite: UserDefaults = .standard) { self.name = key self.defaultValue = defaultValue @@ -34,6 +35,7 @@ public final class Defaults { public let name: String public let suite: UserDefaults + /// Create an optional defaults key. public init(_ key: String, suite: UserDefaults = .standard) { self.name = key self.suite = suite @@ -42,65 +44,129 @@ public final class Defaults { fileprivate init() {} - public subscript(key: Defaults.Key) -> T { - get { - return key.suite[key] - } + /// Access a defaults value using a `Defaults.Key`. + public static subscript(key: Defaults.Key) -> T { + get { key.suite[key] } set { key.suite[key] = newValue } } - public subscript(key: Defaults.OptionalKey) -> T? { - get { - return key.suite[key] - } + /// Access a defaults value using a `Defaults.OptionalKey`. + public static subscript(key: Defaults.OptionalKey) -> T? { + get { key.suite[key] } set { key.suite[key] = newValue } } - - public func clear(suite: UserDefaults = .standard) { - for key in suite.dictionaryRepresentation().keys { - 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 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: 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) { + /** + 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: [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 the given optional keys back to `nil`. + + - Parameter keys: Keys to reset. + - Parameter suite: `UserDefaults` suite. + + ``` + extension Defaults.Keys { + static let unicorn = OptionalKey("unicorn") + } + + Defaults[.unicorn] = "🦄" + + Defaults.reset(.unicorn) + + Defaults[.unicorn] + //=> nil + ``` + */ + public static 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) { + /** + Reset the given array of optional keys back to `nil`. + + - Parameter keys: Keys to reset. + - Parameter suite: `UserDefaults` suite. + + ``` + extension Defaults.Keys { + static let unicorn = OptionalKey("unicorn") + } + + Defaults[.unicorn] = "🦄" + + Defaults.reset(.unicorn) + + Defaults[.unicorn] + //=> nil + ``` + */ + public static 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… -public let defaults = Defaults() + /** + Remove all entries from the `UserDefaults` suite. + */ + public static func clear(suite: UserDefaults = .standard) { + for key in suite.dictionaryRepresentation().keys { + suite.removeObject(forKey: key) + } + } +} extension UserDefaults { private func _get(_ key: String) -> T? { @@ -147,18 +213,14 @@ extension UserDefaults { } public subscript(key: Defaults.Key) -> T { - get { - return _get(key.name) ?? key.defaultValue - } + get { _get(key.name) ?? key.defaultValue } set { _set(key.name, to: newValue) } } public subscript(key: Defaults.OptionalKey) -> T? { - get { - return _get(key.name) - } + get { _get(key.name) } set { guard let value = newValue else { set(nil, forKey: key.name) diff --git a/Sources/Defaults/Observation.swift b/Sources/Defaults/Observation.swift index 2f6c82e..5824528 100644 --- a/Sources/Defaults/Observation.swift +++ b/Sources/Defaults/Observation.swift @@ -117,20 +117,20 @@ extension Defaults { } /** - Observe a defaults key + Observe a defaults key. ``` extension Defaults.Keys { static let isUnicornMode = Key("isUnicornMode", default: false) } - let observer = defaults.observe(.isUnicornMode) { change in + let observer = Defaults.observe(.isUnicornMode) { change in print(change.newValue) //=> false } ``` */ - public func observe( + public static func observe( _ key: Defaults.Key, options: NSKeyValueObservingOptions = [.initial, .old, .new], handler: @escaping (KeyChange) -> Void @@ -145,20 +145,20 @@ extension Defaults { } /** - Observe an optional defaults key + Observe an optional defaults key. ``` extension Defaults.Keys { static let isUnicornMode = OptionalKey("isUnicornMode") } - let observer = defaults.observe(.isUnicornMode) { change in + let observer = Defaults.observe(.isUnicornMode) { change in print(change.newValue) //=> Optional(nil) } ``` */ - public func observe( + public static func observe( _ key: Defaults.OptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new], handler: @escaping (OptionalKeyChange) -> Void diff --git a/Tests/DefaultsTests/DefaultsTests.swift b/Tests/DefaultsTests/DefaultsTests.swift index 9ca912e..93de653 100644 --- a/Tests/DefaultsTests/DefaultsTests.swift +++ b/Tests/DefaultsTests/DefaultsTests.swift @@ -24,30 +24,30 @@ extension Defaults.Keys { final class DefaultsTests: XCTestCase { override func setUp() { super.setUp() - defaults.clear() + Defaults.clear() } override func tearDown() { super.setUp() - defaults.clear() + Defaults.clear() } func testKey() { let key = Defaults.Key("independentKey", default: false) - XCTAssertFalse(defaults[key]) - defaults[key] = true - XCTAssertTrue(defaults[key]) + XCTAssertFalse(Defaults[key]) + Defaults[key] = true + XCTAssertTrue(Defaults[key]) } func testOptionalKey() { let key = Defaults.OptionalKey("independentOptionalKey") - XCTAssertNil(defaults[key]) - defaults[key] = true - XCTAssertTrue(defaults[key]!) - defaults[key] = nil - XCTAssertNil(defaults[key]) - defaults[key] = false - XCTAssertFalse(defaults[key]!) + XCTAssertNil(Defaults[key]) + Defaults[key] = true + XCTAssertTrue(Defaults[key]!) + Defaults[key] = nil + XCTAssertNil(Defaults[key]) + Defaults[key] = false + XCTAssertFalse(Defaults[key]!) } func testKeyRegistersDefault() { @@ -56,7 +56,7 @@ final class DefaultsTests: XCTestCase { _ = Defaults.Key(keyName, default: true) XCTAssertEqual(UserDefaults.standard.bool(forKey: keyName), true) - // Test that it works with multiple keys with defaults + // Test that it works with multiple keys with Defaults. let keyName2 = "registersDefault2" _ = Defaults.Key(keyName2, default: keyName2) XCTAssertEqual(UserDefaults.standard.string(forKey: keyName2), keyName2) @@ -70,56 +70,56 @@ final class DefaultsTests: XCTestCase { } func testKeys() { - XCTAssertFalse(defaults[.key]) - defaults[.key] = true - XCTAssertTrue(defaults[.key]) + XCTAssertFalse(Defaults[.key]) + Defaults[.key] = true + XCTAssertTrue(Defaults[.key]) } func testUrlType() { - XCTAssertEqual(defaults[.url], fixtureURL) + XCTAssertEqual(Defaults[.url], fixtureURL) let newUrl = URL(string: "https://twitter.com")! - defaults[.url] = newUrl - XCTAssertEqual(defaults[.url], newUrl) + Defaults[.url] = newUrl + XCTAssertEqual(Defaults[.url], newUrl) } func testEnumType() { - XCTAssertEqual(defaults[.enum], FixtureEnum.oneHour) + XCTAssertEqual(Defaults[.enum], FixtureEnum.oneHour) } func testDataType() { - XCTAssertEqual(defaults[.data], Data([])) + XCTAssertEqual(Defaults[.data], Data([])) let newData = Data([0xFF]) - defaults[.data] = newData - XCTAssertEqual(defaults[.data], newData) + Defaults[.data] = newData + XCTAssertEqual(Defaults[.data], newData) } func testDateType() { - XCTAssertEqual(defaults[.date], fixtureDate) + XCTAssertEqual(Defaults[.date], fixtureDate) let newDate = Date() - defaults[.date] = newDate - XCTAssertEqual(defaults[.date], newDate) + Defaults[.date] = newDate + XCTAssertEqual(Defaults[.date], newDate) } func testClear() { let key = Defaults.Key("clear", default: false) - defaults[key] = true - XCTAssertTrue(defaults[key]) - defaults.clear() - XCTAssertFalse(defaults[key]) + Defaults[key] = true + XCTAssertTrue(Defaults[key]) + Defaults.clear() + XCTAssertFalse(Defaults[key]) } func testCustomSuite() { let customSuite = UserDefaults(suiteName: "com.sindresorhus.customSuite")! let key = Defaults.Key("customSuite", default: false, suite: customSuite) XCTAssertFalse(customSuite[key]) - XCTAssertFalse(defaults[key]) - defaults[key] = true + XCTAssertFalse(Defaults[key]) + Defaults[key] = true XCTAssertTrue(customSuite[key]) - XCTAssertTrue(defaults[key]) - defaults.clear(suite: customSuite) + XCTAssertTrue(Defaults[key]) + Defaults.clear(suite: customSuite) } func testObserveKey() { @@ -127,14 +127,14 @@ final class DefaultsTests: XCTestCase { let expect = expectation(description: "Observation closure being called") var observation: DefaultsObservation! - observation = defaults.observe(key, options: [.old, .new]) { change in + observation = Defaults.observe(key, options: [.old, .new]) { change in XCTAssertFalse(change.oldValue) XCTAssertTrue(change.newValue) observation.invalidate() expect.fulfill() } - defaults[key] = true + Defaults[key] = true waitForExpectations(timeout: 10) } @@ -144,14 +144,14 @@ final class DefaultsTests: XCTestCase { let expect = expectation(description: "Observation closure being called") var observation: DefaultsObservation! - observation = defaults.observe(key, options: [.old, .new]) { change in + observation = Defaults.observe(key, options: [.old, .new]) { change in XCTAssertNil(change.oldValue) XCTAssertTrue(change.newValue!) observation.invalidate() expect.fulfill() } - defaults[key] = true + Defaults[key] = true waitForExpectations(timeout: 10) } @@ -163,14 +163,14 @@ final class DefaultsTests: XCTestCase { let expect = expectation(description: "Observation closure being called") var observation: DefaultsObservation! - observation = defaults.observe(key, options: [.old, .new]) { change in + observation = Defaults.observe(key, options: [.old, .new]) { change in XCTAssertEqual(change.oldValue, fixtureURL) XCTAssertEqual(change.newValue, fixtureURL2) observation.invalidate() expect.fulfill() } - defaults[key] = fixtureURL2 + Defaults[key] = fixtureURL2 waitForExpectations(timeout: 10) } @@ -180,14 +180,14 @@ final class DefaultsTests: XCTestCase { let expect = expectation(description: "Observation closure being called") var observation: DefaultsObservation! - observation = defaults.observe(key, options: [.old, .new]) { change in + observation = Defaults.observe(key, options: [.old, .new]) { change in XCTAssertEqual(change.oldValue, .oneHour) XCTAssertEqual(change.newValue, .tenMinutes) observation.invalidate() expect.fulfill() } - defaults[key] = .tenMinutes + Defaults[key] = .tenMinutes waitForExpectations(timeout: 10) } @@ -199,11 +199,11 @@ final class DefaultsTests: XCTestCase { 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) + Defaults[key1] = newString1 + Defaults[key2] = newString2 + Defaults.reset(key1) + XCTAssertEqual(Defaults[key1], defaultString1) + XCTAssertEqual(Defaults[key2], newString2) } func testResetKeyArray() { @@ -216,13 +216,13 @@ final class DefaultsTests: XCTestCase { 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) + 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() { @@ -230,11 +230,11 @@ final class DefaultsTests: XCTestCase { 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) + Defaults[key1] = newString1 + Defaults[key2] = newString2 + Defaults.reset(key1) + XCTAssertEqual(Defaults[key1], nil) + XCTAssertEqual(Defaults[key2], newString2) } func testResetOptionalKeyArray() { @@ -244,12 +244,12 @@ final class DefaultsTests: XCTestCase { 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) + 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 e4931d8..81a8c2b 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ > Swifty and modern [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults) -This package is used in production by the [Lungo](https://sindresorhus.com/lungo), [Battery Indicator](https://sindresorhus.com/battery-indicator), and [HEIC Converter](https://sindresorhus.com/heic-converter) app. +This package is used in production by the [Gifski](https://github.com/sindresorhus/Gifski), [Lungo](https://sindresorhus.com/lungo), [Battery Indicator](https://sindresorhus.com/battery-indicator), and [HEIC Converter](https://sindresorhus.com/heic-converter) app. ## Highlights @@ -58,19 +58,19 @@ extension Defaults.Keys { } ``` -You can then access it as a subscript on the `defaults` global (note lowercase): +You can then access it as a subscript on the `Defaults` global: ```swift -defaults[.quality] +Defaults[.quality] //=> 0.8 -defaults[.quality] = 0.5 +Defaults[.quality] = 0.5 //=> 0.5 -defaults[.quality] += 0.1 +Defaults[.quality] += 0.1 //=> 0.6 -defaults[.quality] = "🦄" +Defaults[.quality] = "🦄" //=> [Cannot assign value of type 'String' to type 'Double'] ``` @@ -81,7 +81,7 @@ extension Defaults.Keys { static let name = OptionalKey("name") } -if let name = defaults[.name] { +if let name = Defaults[.name] { print(name) } ``` @@ -101,7 +101,7 @@ extension Defaults.Keys { static let defaultDuration = Key("defaultDuration", default: .oneHour) } -defaults[.defaultDuration].rawValue +Defaults[.defaultDuration].rawValue //=> "1 Hour" ``` @@ -127,7 +127,7 @@ extension Defaults.Keys { static let isUnicorn = Key("isUnicorn", default: true, suite: extensionDefaults) } -defaults[.isUnicorn] +Defaults[.isUnicorn] //=> true // Or @@ -143,7 +143,7 @@ You are not required to attach keys to `Defaults.Keys`. ```swift let isUnicorn = Defaults.Key("isUnicorn", default: true) -defaults[isUnicorn] +Defaults[isUnicorn] //=> true ``` @@ -154,7 +154,7 @@ extension Defaults.Keys { static let isUnicornMode = Key("isUnicornMode", default: false) } -let observer = defaults.observe(.isUnicornMode) { change in +let observer = Defaults.observe(.isUnicornMode) { change in // Initial event print(change.oldValue) //=> false @@ -168,7 +168,7 @@ let observer = defaults.observe(.isUnicornMode) { change in //=> true } -defaults[.isUnicornMode] = true +Defaults[.isUnicornMode] = true ``` In contrast to the native `UserDefaults` key observation, here you receive a strongly-typed change object. @@ -180,12 +180,12 @@ extension Defaults.Keys { static let isUnicornMode = Key("isUnicornMode", default: false) } -defaults[.isUnicornMode] = true +Defaults[.isUnicornMode] = true //=> true -defaults.reset(.isUnicornMode) +Defaults.reset(.isUnicornMode) -defaults[.isUnicornMode] +Defaults[.isUnicornMode] //=> false ``` @@ -207,7 +207,7 @@ print(UserDefaults.standard.bool(forKey: isUnicornMode.name)) ## API -### `let defaults = Defaults()` +### `Defaults` #### `Defaults.Keys` @@ -225,7 +225,7 @@ Type: `class` Create a key with a default value. -The default value is written to the actual `UserDefaults` and can be used elsewhere. For example, with Interface Builder binding. +The default value is written to the actual `UserDefaults` and can be used elsewhere. For example, with a Interface Builder binding. #### `Defaults.OptionalKey` *(alias `Defaults.Keys.OptionalKey`)* @@ -237,20 +237,23 @@ Type: `class` Create a key with an optional value. -#### `Defaults#clear` +#### `Defaults.reset` ```swift -clear(suite: UserDefaults = .standard) +Defaults.reset(_ keys: Defaults.Key..., suite: UserDefaults = .standard) +Defaults.reset(_ keys: [Defaults.Key], suite: UserDefaults = .standard) +Defaults.reset(_ keys: Defaults.OptionalKey..., suite: UserDefaults = .standard) +Defaults.reset(_ keys: [Defaults.OptionalKey], suite: UserDefaults = .standard) ``` Type: `func` -Clear the user defaults. +Reset the given keys back to their default values. -#### `Defaults#observe` +#### `Defaults.observe` ```swift -observe( +Defaults.observe( _ key: Defaults.Key, options: NSKeyValueObservingOptions = [.initial, .old, .new], handler: @escaping (KeyChange) -> Void @@ -258,7 +261,7 @@ observe( ``` ```swift -observe( +Defaults.observe( _ key: Defaults.OptionalKey, options: NSKeyValueObservingOptions = [.initial, .old, .new], handler: @escaping (OptionalKeyChange) -> Void @@ -271,6 +274,16 @@ Observe changes to a key or an optional key. By default, it will also trigger an initial event on creation. This can be useful for setting default values on controls. You can override this behavior with the `options` argument. +#### `Defaults.clear` + +```swift +Defaults.clear(suite: UserDefaults = .standard) +``` + +Type: `func` + +Clear the user defaults. + ## FAQ