Switch to static subscript on `Defaults`
This commit is contained in:
parent
d1e42154f9
commit
90ac6f8802
|
@ -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'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
59
readme.md
59
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<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
|
||||
|
||||
|
|
Loading…
Reference in New Issue