This package is part of the SNAP suite.
A single interface to handle different types of settings. It stores a Codable type for a String key, either locally (UserDefaults), synced (NSUbiquitousKeyValueStore) or in a custom store.
This package provides the SettingsService class, SettingsStore protocol and helper to define, save and read settings.
To support settings stored in iCloud (NSUbiquitousKeyValueStore) you have to add the iCloud Capability to the target and enable the Key-value storage checkbox.
The demo project shows an example usage of the SettingsService with settings in different scopes.
Define your settings:
extension SettingsService.SettingDefinition {
static let exampleNumber = SettingsService.Setting<Int>("ExampleNumber", in: .defaults, default: 1)
}
Read and write the settings:
let settings = SettingsService()
settings.set(.exampleNumber, to: 2)
let number = settings.get(.exampleNumber)
Use the binding, when you need it to update on changes:
struct MyView: View {
let observableValue: SettingsService.Value<Int> = settings.value(.exampleNumber)
var body: some View {
Text("\(observableValue.value)")
SomeView(binding: observableValue.binding)
}
}
The SettingsService can be configured with a SettingsStore object for a Scope: .defaults, .ubiquitous, .custom(id:)
SettingsService.init(defaults: UserDefaults? = .standard, ubiquitous: NSUbiquitousKeyValueStore? = .default, storesForCustomScopes: [Scope : SettingsStore] = [:])
Stored locally in UserDefaults.
// TODO: How to handle privacy requirements.
Stored in iCloud using NSUbiquitousKeyValueStore.
If user is not logged in, the value is stored locally and a warning is logged.
To use NSUbiquitousKeyValueStore, you must distribute your app through the App Store or Mac App Store, and you must request the com.apple.developer.ubiquity-kvstore-identifier entitlement in your Xcode project. NSUbiquitousKeyValueStore Documentation
(see Setup)
You can provide one or multiple custom stores that implement SettingsStore.
If there is no store registered for the scope, a warning is logged.
UserDefaults and NSUbiquitousKeyValueStore are extended to conform to SettingsStore.
You can create a custom store by implementing SettingsStore.
public protocol SettingsStore {
func get<T>(_ key: SettingsService.Setting<T>) -> Data?
func set<T>(_ key: SettingsService.Setting<T>, to data: Data?)
}
let settings = SettingsService()
settings.set(.exampleNumber, to: 2)
let number = settings.get(.exampleNumber)
struct MyView: View {
let observableValue: SettingsService.Value<Int> = settings.value(.exampleNumber)
var body: some View {
Text("\(observableValue.value)")
SomeView(binding: observableValue.binding)
}
}
The SettingsService provides a Combine publisher to receive updated values. If the setting is stored in the .ubiquitous scope, the publisher is updated on remote changes (NSUbiquitousKeyValueStore.didChangeExternallyNotification).
The SettingsService can be used by the provided EnvironmentKey.
Inject into the @Environment:
@Environment(\.serviceSettings) private var settings
Access from @Environment:
View().environment(\.serviceSettings, settings)
// TODO: App Groups? Access in Widget? // TODO: Handle iCloud not available. It does store locally and logs a warning, but should do something?
