Fix `Defaults.reset()`

This commit is contained in:
Sindre Sorhus 2020-04-17 22:32:44 +08:00
parent 77c05abe10
commit 15c096d7fd
9 changed files with 1335 additions and 313 deletions

View File

@ -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 = "<group>"; usesTabs = 1; };
E339B3B22449ED2000E7A40A /* Reset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Reset.swift; sourceTree = "<group>"; usesTabs = 1; };
E339B3B72449F10D00E7A40A /* UserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserDefaults.swift; sourceTree = "<group>"; usesTabs = 1; };
E3EB3E32216505920033B089 /* util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = util.swift; sourceTree = "<group>"; usesTabs = 1; };
E3EB3E34216507AE0033B089 /* Observation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Observation.swift; sourceTree = "<group>"; 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;
};

View File

@ -26,20 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DD7502791C68FCFC006590AF"
BuildableName = "Defaults-macOS Tests.xctest"
BlueprintName = "Defaults-macOS Tests"
ReferencedContainer = "container:Defaults.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -49,8 +37,20 @@
ReferencedContainer = "container:Defaults.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DD7502791C68FCFC006590AF"
BuildableName = "Defaults-macOS Tests.xctest"
BlueprintName = "Defaults-macOS Tests"
ReferencedContainer = "container:Defaults.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -71,8 +71,6 @@
ReferencedContainer = "container:Defaults.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -1,6 +1,18 @@
// MIT License © Sindre Sorhus
import Foundation
public protocol _DefaultsBaseKey: Defaults.Keys {
var name: String { get }
var suite: UserDefaults { get }
}
extension _DefaultsBaseKey {
/// Reset the item back to its default value.
public func reset() {
suite.removeObject(forKey: name)
}
}
public enum Defaults {
public class Keys {
public typealias Key = Defaults.Key
@ -14,7 +26,7 @@ public enum Defaults {
fileprivate init() {}
}
public final class Key<Value: Codable>: Keys {
public final class Key<Value: Codable>: 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<Value: NSSecureCoding>: Keys {
public final class NSSecureCodingKey<Value: NSSecureCoding>: 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<Value: NSSecureCoding>: Keys {
public final class NSSecureCodingOptionalKey<Value: NSSecureCoding>: 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<Bool>("isUnicornMode", default: false)
}
Defaults[.isUnicornMode] = true
//=> true
Defaults.reset(.isUnicornMode)
Defaults[.isUnicornMode]
//=> false
```
*/
public static func reset<Value: Codable>(_ keys: Key<Value>..., 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<Value: NSSecureCoding>(_ keys: NSSecureCodingKey<Value>..., 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<Bool>("isUnicornMode", default: false)
}
Defaults[.isUnicornMode] = true
//=> true
Defaults.reset(.isUnicornMode)
Defaults[.isUnicornMode]
//=> false
```
*/
public static func reset<Value: Codable>(_ keys: [Key<Value>], 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<Value: NSSecureCoding>(_ keys: [NSSecureCodingKey<Value>], 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<Value: NSSecureCoding>(_ keys: NSSecureCodingOptionalKey<Value>..., 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<Value: NSSecureCoding>(_ keys: [NSSecureCodingOptionalKey<Value>], 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<Value: Codable>(_ 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<Value: NSSecureCoding>(_ 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: Codable>(_ 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<Value: Codable>(_ 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<Value: NSSecureCoding>(_ 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<Value: Codable>(key: Defaults.Key<Value>) -> 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<Value: NSSecureCoding>(key: Defaults.NSSecureCodingKey<Value>) -> 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<Value: NSSecureCoding>(key: Defaults.NSSecureCodingOptionalKey<Value>) -> 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<T>(_ 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
}
}
}

View File

@ -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<Value: Codable>(
keys:Key<Value>...,
keys: Key<Value>...,
options: ObservationOptions = [.initial]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(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<Value: NSSecureCoding>(
keys: Defaults.NSSecureCodingKey<Value>...,
keys: NSSecureCodingKey<Value>...,
options: ObservationOptions = [.initial]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(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<Value: NSSecureCoding>(
keys: Defaults.NSSecureCodingOptionalKey<Value>...,
keys: NSSecureCodingOptionalKey<Value>...,
options: ObservationOptions = [.initial]
) -> AnyPublisher<Void, Never> {
let initial = Empty<Void, Never>(completeImmediately: false).eraseToAnyPublisher()

View File

@ -226,7 +226,7 @@ extension Defaults {
) -> Observation {
let observation = UserDefaultsKeyObservation(object: key.suite, key: key.name) { change in
handler(
KeyChange<Value>(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<Value>(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<Value>(change: change)
NSSecureCodingOptionalKeyChange(change: change)
)
}
observation.start(options: options)

1094
Sources/Defaults/Reset.swift Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,134 @@
import Foundation
extension UserDefaults {
private func _get<Value: Codable>(_ 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<Value: NSSecureCoding>(_ 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: Codable>(_ 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<Value: Codable>(_ 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<Value: NSSecureCoding>(_ 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<Value: Codable>(key: Defaults.Key<Value>) -> 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<Value: NSSecureCoding>(key: Defaults.NSSecureCodingKey<Value>) -> 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<Value: NSSecureCoding>(key: Defaults.NSSecureCodingOptionalKey<Value>) -> 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<T>(_ 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
}
}
}

View File

@ -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<String>("key1", default: defaultString1)
let key2 = Defaults.Key<String>("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<String>("key1", default: defaultFixture1)
let key2 = Defaults.Key<Int>("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<ExamplePersistentHistory>("key3", default: ExamplePersistentHistory(value: defaultString3))
Defaults[key3] = ExamplePersistentHistory(value: newString3)
let key3 = Defaults.NSSecureCodingKey<ExamplePersistentHistory>("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<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
func testResetMultipleKeys() {
let defaultFxiture1 = "foo1"
let defaultFixture2 = 0
let defaultFixture3 = "foo3"
let newFixture1 = "bar1"
let newFixture2 = 1
let newFixture3 = "bar3"
let key1 = Defaults.Key<String>("akey1", default: defaultFxiture1)
let key2 = Defaults.Key<Int>("akey2", default: defaultFixture2)
let key3 = Defaults.Key<String>("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<String?>("aoptionalKey1")
let key2 = Defaults.Key<String?>("aoptionalKey2")
let key2 = Defaults.Key<Int?>("aoptionalKey2")
let key3 = Defaults.Key<String?>("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() {

View File

@ -318,22 +318,16 @@ Type: `class`
Create a NSSecureCoding key with an optional value.
#### `Defaults.reset`
```swift
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.NSSecureCodingKey<T>..., suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: [Defaults.NSSecureCodingKey<T>], suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: Defaults.NSSecureCodingOptionalKey<T>..., suite: UserDefaults = .standard)
Defaults.reset<T: Codable>(_ keys: [Defaults.NSSecureCodingOptionalKey<T>], 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`