Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support NSUbiquitousKeyValueStore #75

Closed
sindresorhus opened this issue Jun 15, 2021 · 12 comments · Fixed by #136
Closed

Support NSUbiquitousKeyValueStore #75

sindresorhus opened this issue Jun 15, 2021 · 12 comments · Fixed by #136
Assignees

Comments

@sindresorhus
Copy link
Owner

sindresorhus commented Jun 15, 2021

https://developer.apple.com/documentation/foundation/nsubiquitouskeyvaluestore

It would be nice to be able to mark keys as being sync'able and have them be automatically synced with iCloud. Syncing settings/data is a very common need, but it's currently difficult to get right. We could make it super easy.

UserDefaults would still be the main storage, as per Apple docs:

Avoid using this class for data that is essential to your app’s behavior when offline; instead, store such data directly into the local user defaults database.


We could take some inspiration from https://github.com/ArtSabintsev/Zephyr:

// Add keys to be automatically synced.
Defaults.iCloud.add(.foo, .bar)

// Remove keys to be automatically synced.
Defaults.iCloud.remove(.foo)

// Lists the synced keys.
Defaults.iCloud.keys

// Force sync all added keys.
Defaults.iCloud.sync()

We could also make a key syncable by default:

extension Defaults.Keys {
	static let quality = Key<Double>("quality", default: 0.8, iCloud: true)

}

@hank121314 Thoughts on the idea and the API?

@sindresorhus
Copy link
Owner Author

@hank121314 Any thoughts on this? (Not asking you to do the work. Just want to make sure we end up with the optimal solution)

@hank121314 hank121314 assigned hank121314 and unassigned hank121314 Oct 25, 2021
@hank121314
Copy link
Collaborator

hank121314 commented Oct 25, 2021

The APIs above look good 😃 .
I think we might also need to add an observation for NSUbiquitousKeyValueStore.didChangeExternallyNotification.
Maybe like this:

Defaults.iCloud.observe(.quality) { change in
	print(change.newValue)
}

For Combine:

let publisher = Defaults.iCloud.publisher(.quality).map(\.newValue)

And as per Apple docs:

The only recommended time to call this method is upon app launch, or upon returning to the foreground, to ensure that the in-memory key-value store representation is up-to-date.

ArtSabintsev/Zephyr synchronize NSUbiquitousKeyValueStore when willEnterForegroundNotification is triggered.

Should we also do this in Defaults?

@sindresorhus
Copy link
Owner Author

think we might also need to add an observation for NSUbiquitousKeyValueStore.didChangeExternallyNotification.

I was thinking that we handle that internally. The user would just use Defaults.publisher, which would also be triggered by that notification.

The point of this feature is to handle the sync automatically. All the user has to do is to provide the set of keys that should be synced. Everything else is just normal Defaults usage.

Should we also do this in Defaults?

Yeah, I think so.

@hank121314
Copy link
Collaborator

I was thinking that we handle that internally. The user would just use Defaults.publisher, which would also be triggered by that notification.

Got it! Maybe we can add a new ObservationOption for this notification?
It will be useful for users to recognize this notification.

For example:

Defaults.publisher(.key, options: [.iCloud or .sync])

@sindresorhus
Copy link
Owner Author

Maybe we can add a new ObservationOption for this notification?

What's the use-case?

@hank121314
Copy link
Collaborator

What's the use-case?

I am not sure what kinds of use-case honestly.
But this will be more convenient for those who only want to listen to the NSUbiquitousKeyValueStore.didChangeExternallyNotification notification.

@sindresorhus
Copy link
Owner Author

Yes, but I'm curious why people would need to listen to NSUbiquitousKeyValueStore.didChangeExternallyNotification, since with my proposed solution, that event is just handled for them, so they don't need to care.

I feel like we're maybe talking past each other. With my solution, Defaults would listen to NSUbiquitousKeyValueStore.didChangeExternallyNotification internally, fetch the changes, merge them in, and then trigger a normal defaults update. From the user's perspective, they just use Defaults like they always have, but they now have full syncing included for free without any extra work, other than registering the keys they want synced.

@hank121314
Copy link
Collaborator

Defaults would listen to NSUbiquitousKeyValueStore.didChangeExternallyNotification internally, fetch the changes, merge them in, and then trigger a normal defaults update. From the user's perspective, they just use Defaults like they always have, but they now have full syncing included for free without any extra work, other than registering the keys they want synced.

Yeah! That's the main feature.
But I would like to let users know who make the changes.
With Defaults.publisher(.key, options: [.iCloud or .sync]) they will be able to know this change was made by remote synchroization.

@sindresorhus
Copy link
Owner Author

I think a property on the Observation object would be better. Maybe .isSyncUpdate. But I would wait until someone has an actual need for this. It would be easier to design a solution around an actual need than trying to anticipate what users will need.

@hank121314
Copy link
Collaborator

But I would wait until someone has an actual need for this.

Yeah! Let's just keep an open mind to this additional feature.

It would be easier to design a solution around an actual need than trying to anticipate what users will need.

That's true 👍. Learn a lot from it 😃 !

@Pomanks
Copy link

Pomanks commented Feb 24, 2022

It was missing by the time I needed it so I implemented something on my own (locally) for now but it's not as deeply integrated as what you plan on adding and relies on me checking for NSUbiquitousKeyValueStore.didChangeExternallyNotification and updating the values then so… please let me know if I can help! 😄

@sindresorhus
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants