Switch to static subscript on `Defaults`

This commit is contained in:
Sindre Sorhus 2019-09-11 11:59:28 +07:00
parent d1e42154f9
commit 90ac6f8802
6 changed files with 213 additions and 154 deletions

View File

@ -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'

View File

@ -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 = "<group>"; };
6614F6E222FC6E1C00B0C9CE /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; lineEnding = 0; path = readme.md; sourceTree = "<group>"; usesTabs = 1; };
8933C7841EB5B820000D00A4 /* Defaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Defaults.swift; sourceTree = "<group>"; usesTabs = 1; };
8933C7891EB5B82A000D00A4 /* DefaultsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DefaultsTests.swift; sourceTree = "<group>"; usesTabs = 1; };
AD2FAA261CD0B6D800659CF4 /* Defaults.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Defaults.plist; sourceTree = "<group>"; };
@ -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;

View File

@ -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<T: Codable>(key: Defaults.Key<T>) -> T {
get {
return key.suite[key]
}
/// Access a defaults value using a `Defaults.Key`.
public static subscript<T: Codable>(key: Defaults.Key<T>) -> T {
get { key.suite[key] }
set {
key.suite[key] = newValue
}
}
public subscript<T: Codable>(key: Defaults.OptionalKey<T>) -> T? {
get {
return key.suite[key]
}
/// Access a defaults value using a `Defaults.OptionalKey`.
public static subscript<T: Codable>(key: Defaults.OptionalKey<T>) -> 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<T: Codable>(_ keys: Defaults.Key<T>..., 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<Bool>("isUnicornMode", default: false)
}
Defaults[.isUnicornMode] = true
//=> true
Defaults.reset(.isUnicornMode)
Defaults[.isUnicornMode]
//=> false
```
*/
public static func reset<T: Codable>(_ keys: Defaults.Key<T>..., 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<T: Codable>(_ keys: [Defaults.Key<T>], 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<Bool>("isUnicornMode", default: false)
}
Defaults[.isUnicornMode] = true
//=> true
Defaults.reset(.isUnicornMode)
Defaults[.isUnicornMode]
//=> false
```
*/
public static func reset<T: Codable>(_ keys: [Defaults.Key<T>], 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<T: Codable>(_ keys: Defaults.OptionalKey<T>..., 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<String>("unicorn")
}
Defaults[.unicorn] = "🦄"
Defaults.reset(.unicorn)
Defaults[.unicorn]
//=> nil
```
*/
public static func reset<T: Codable>(_ keys: Defaults.OptionalKey<T>..., 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<T: Codable>(_ keys: [Defaults.OptionalKey<T>], 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<String>("unicorn")
}
Defaults[.unicorn] = "🦄"
Defaults.reset(.unicorn)
Defaults[.unicorn]
//=> nil
```
*/
public static func reset<T: Codable>(_ keys: [Defaults.OptionalKey<T>], 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<T: Codable>(_ key: String) -> T? {
@ -147,18 +213,14 @@ extension UserDefaults {
}
public subscript<T: Codable>(key: Defaults.Key<T>) -> T {
get {
return _get(key.name) ?? key.defaultValue
}
get { _get(key.name) ?? key.defaultValue }
set {
_set(key.name, to: newValue)
}
}
public subscript<T: Codable>(key: Defaults.OptionalKey<T>) -> T? {
get {
return _get(key.name)
}
get { _get(key.name) }
set {
guard let value = newValue else {
set(nil, forKey: key.name)

View File

@ -117,20 +117,20 @@ extension Defaults {
}
/**
Observe a defaults key
Observe a defaults key.
```
extension Defaults.Keys {
static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
}
let observer = defaults.observe(.isUnicornMode) { change in
let observer = Defaults.observe(.isUnicornMode) { change in
print(change.newValue)
//=> false
}
```
*/
public func observe<T: Codable>(
public static func observe<T: Codable>(
_ key: Defaults.Key<T>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (KeyChange<T>) -> Void
@ -145,20 +145,20 @@ extension Defaults {
}
/**
Observe an optional defaults key
Observe an optional defaults key.
```
extension Defaults.Keys {
static let isUnicornMode = OptionalKey<Bool>("isUnicornMode")
}
let observer = defaults.observe(.isUnicornMode) { change in
let observer = Defaults.observe(.isUnicornMode) { change in
print(change.newValue)
//=> Optional(nil)
}
```
*/
public func observe<T: Codable>(
public static func observe<T: Codable>(
_ key: Defaults.OptionalKey<T>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (OptionalKeyChange<T>) -> Void

View File

@ -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<Bool>("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<Bool>("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<Bool>(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<String>(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<Bool>("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<Bool>("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<String>("key1", default: defaultString1)
let key2 = Defaults.Key<String>("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<String>("akey1", default: defaultString1)
let key2 = Defaults.Key<String>("akey2", default: defaultString2)
let key3 = Defaults.Key<String>("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<String>("optionalKey1")
let key2 = Defaults.OptionalKey<String>("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<String>("aoptionalKey1")
let key2 = Defaults.OptionalKey<String>("aoptionalKey2")
let key3 = Defaults.OptionalKey<String>("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)
}
}

View File

@ -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<Double>("name")
}
if let name = defaults[.name] {
if let name = Defaults[.name] {
print(name)
}
```
@ -101,7 +101,7 @@ extension Defaults.Keys {
static let defaultDuration = Key<DurationKeys>("defaultDuration", default: .oneHour)
}
defaults[.defaultDuration].rawValue
Defaults[.defaultDuration].rawValue
//=> "1 Hour"
```
@ -127,7 +127,7 @@ extension Defaults.Keys {
static let isUnicorn = Key<Bool>("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<Bool>("isUnicorn", default: true)
defaults[isUnicorn]
Defaults[isUnicorn]
//=> true
```
@ -154,7 +154,7 @@ extension Defaults.Keys {
static let isUnicornMode = Key<Bool>("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<Bool>("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<T: Codable>(_ keys: Defaults.Key<T>..., suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: [Defaults.Key<T>], suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: Defaults.OptionalKey<T>..., suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: [Defaults.OptionalKey<T>], suite: UserDefaults = .standard)
```
Type: `func`
Clear the user defaults.
Reset the given keys back to their default values.
#### `Defaults#observe`
#### `Defaults.observe`
```swift
observe<T: Codable>(
Defaults.observe<T: Codable>(
_ key: Defaults.Key<T>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (KeyChange<T>) -> Void
@ -258,7 +261,7 @@ observe<T: Codable>(
```
```swift
observe<T: Codable>(
Defaults.observe<T: Codable>(
_ key: Defaults.OptionalKey<T>,
options: NSKeyValueObservingOptions = [.initial, .old, .new],
handler: @escaping (OptionalKeyChange<T>) -> 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