Disable syncing from local if its default after `iCloud.add` (#185)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
This commit is contained in:
parent
bf717462d9
commit
174b791fec
|
@ -39,7 +39,7 @@ extension Defaults {
|
|||
|
||||
## Dynamically Toggle Syncing
|
||||
|
||||
You can also toggle the syncing behavior dynamically using the ``Defaults/iCloud/add(_:)-5gffb`` and ``Defaults/iCloud/remove(_:)-1b8w5`` methods.
|
||||
You can also toggle the syncing behavior dynamically using the ``Defaults/iCloud/add(_:)`` and ``Defaults/iCloud/remove(_:)-1b8w5`` methods.
|
||||
|
||||
```swift
|
||||
import Defaults
|
||||
|
@ -82,15 +82,10 @@ extension Defaults {
|
|||
/**
|
||||
Add the keys to be automatically synced.
|
||||
*/
|
||||
public static func add(_ keys: Defaults.Keys...) {
|
||||
synchronizer.add(keys)
|
||||
}
|
||||
|
||||
/**
|
||||
Add the keys to be automatically synced.
|
||||
*/
|
||||
public static func add(_ keys: [Defaults.Keys]) {
|
||||
synchronizer.add(keys)
|
||||
// TODO: Support array of Defaults.Key after Swift 6 pack iteration is supported.
|
||||
// https://github.com/sindresorhus/Defaults/pull/185#discussion_r1704464183
|
||||
public static func add<each Value: Defaults.Serializable>(_ keys: repeat Defaults.Key<each Value>) {
|
||||
repeat synchronizer.add(each keys)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,11 +264,23 @@ final class iCloudSynchronizer {
|
|||
/**
|
||||
Add new key and start to observe its changes.
|
||||
*/
|
||||
func add(_ keys: [Defaults.Keys]) {
|
||||
self.keys.formUnion(keys)
|
||||
syncWithoutWaiting(keys)
|
||||
for key in keys {
|
||||
localKeysMonitor.add(key: key)
|
||||
func add<Value: Defaults.Serializable>(_ key: Defaults.Key<Value>) {
|
||||
let (isInserted, _) = self.keys.insert(key)
|
||||
guard isInserted else {
|
||||
return
|
||||
}
|
||||
|
||||
localKeysMonitor.add(key: key)
|
||||
|
||||
// If the local value is the default value, only sync from remote, since all devices should already have the default value.
|
||||
if key._isDefaultValue {
|
||||
guard case .remote = latestDataSource(forKey: key) else {
|
||||
return
|
||||
}
|
||||
|
||||
syncWithoutWaiting([key], .remote)
|
||||
} else {
|
||||
syncWithoutWaiting([key])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,31 @@ extension Defaults.Key {
|
|||
) where Value == T? {
|
||||
self.init(name, default: nil, suite: suite, iCloud: iCloud)
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the stored value is the default value.
|
||||
|
||||
- Note: This is only for internal use because it would not work for non-equatable values.
|
||||
*/
|
||||
var _isDefaultValue: Bool {
|
||||
let defaultValue = defaultValue
|
||||
let value = suite[self]
|
||||
guard
|
||||
let defaultValue = defaultValue as? any Equatable,
|
||||
let value = value as? any Equatable
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return defaultValue.isEqual(value)
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults.Key where Value: Equatable {
|
||||
/**
|
||||
Check whether the stored value is the default value.
|
||||
*/
|
||||
public var isDefaultValue: Bool { self._isDefaultValue }
|
||||
}
|
||||
|
||||
extension Defaults {
|
||||
|
|
|
@ -165,6 +165,19 @@ extension Collection {
|
|||
}
|
||||
}
|
||||
|
||||
extension Equatable {
|
||||
func isEqual(_ rhs: any Equatable) -> Bool {
|
||||
guard
|
||||
let rhs = rhs as? Self,
|
||||
rhs == self
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Defaults {
|
||||
@usableFromInline
|
||||
static func isValidKeyPath(name: String) -> Bool {
|
||||
|
|
|
@ -88,14 +88,12 @@ final class DefaultsICloudTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testICloudInitialize() async {
|
||||
print(Defaults.iCloud.keys)
|
||||
let name = Defaults.Key<String>("testICloudInitialize_name", default: "0", iCloud: true)
|
||||
let quality = Defaults.Key<Double>("testICloudInitialize_quality", default: 0.0, iCloud: true)
|
||||
|
||||
print(Defaults.iCloud.keys)
|
||||
await Defaults.iCloud.waitForSyncCompletion()
|
||||
XCTAssertEqual(mockStorage.data(forKey: name.name), "0")
|
||||
XCTAssertEqual(mockStorage.data(forKey: quality.name), 0.0)
|
||||
XCTAssertNil(mockStorage.data(forKey: name.name))
|
||||
XCTAssertNil(mockStorage.data(forKey: quality.name))
|
||||
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
|
||||
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
|
||||
|
||||
|
@ -251,8 +249,9 @@ final class DefaultsICloudTests: XCTestCase {
|
|||
|
||||
func testAddFromDetached() async {
|
||||
let name = Defaults.Key<String>("testInitAddFromDetached_name", default: "0")
|
||||
let quantity = Defaults.Key<Bool>("testInitAddFromDetached_quantity", default: false)
|
||||
let task = Task.detached {
|
||||
Defaults.iCloud.add(name)
|
||||
Defaults.iCloud.add(name, quantity)
|
||||
Defaults.iCloud.syncWithoutWaiting()
|
||||
await Defaults.iCloud.waitForSyncCompletion()
|
||||
}
|
||||
|
@ -268,7 +267,7 @@ final class DefaultsICloudTests: XCTestCase {
|
|||
let name = Defaults.Key<String>("testICloudInitializeFromDetached_name", default: "0", iCloud: true)
|
||||
|
||||
await Defaults.iCloud.waitForSyncCompletion()
|
||||
XCTAssertEqual(mockStorage.data(forKey: name.name), "0")
|
||||
XCTAssertNil(mockStorage.data(forKey: name.name))
|
||||
}
|
||||
await task.value
|
||||
}
|
||||
|
|
|
@ -177,6 +177,13 @@ final class DefaultsTests: XCTestCase {
|
|||
Defaults.removeAll(suite: customSuite)
|
||||
}
|
||||
|
||||
func testIsDefaultValue() {
|
||||
let key = Defaults.Key<Bool>("isDefaultValue", default: false)
|
||||
XCTAssert(key.isDefaultValue)
|
||||
Defaults[key].toggle()
|
||||
XCTAssert(!key.isDefaultValue)
|
||||
}
|
||||
|
||||
func testObserveKeyCombine() {
|
||||
let key = Defaults.Key<Bool>("observeKey", default: false)
|
||||
let expect = expectation(description: "Observation closure being called")
|
||||
|
|
Loading…
Reference in New Issue