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?