simonnickel/snap-settings-service
This package is part of the SNAP suite.
Requirements
- iOS 18+, macOS 15+
- Swift 6.3
- Dependencies: snap-core
Setup
To support settings stored in iCloud (NSUbiquitousKeyValueStore) you have to add the iCloud Capability to the target and enable the Key-value storage checkbox.
Demo project
The demo project shows an example usage of the SettingsService with settings in different scopes.
<img src="/screenshot.png" height="400">
Usage
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 (value(_:) is @MainActor):
struct MyView: View {
let observableValue: SettingsService.Value<Int> = settings.value(.exampleNumber)
var body: some View {
Text("\(observableValue.value)")
SomeView(binding: observableValue.binding)
}
}Scope
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] = [:]).defaults
Stored locally in UserDefaults.
How to handle privacy requirements is open, see TODO-5.
.ubiquitous
Stored in iCloud using NSUbiquitousKeyValueStore.
If iCloud is unavailable, NSUbiquitousKeyValueStore stores values locally as a fallback — SettingsService is not involved in that fallback. A warning is only logged if no store is registered for the scope at all. Handling this case is open, see TODO-2.
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)
.custom(id:)
You can provide one or multiple custom stores that implement SettingsStore.
If there is no store registered for the scope, a warning is logged.
SettingsStore
UserDefaults and NSUbiquitousKeyValueStore are extended to conform to SettingsStore.
Custom
You can create a custom store by implementing SettingsStore.
public protocol SettingsStore {
func get(_ key: SettingsService.StorageKey) -> Data?
func set(_ key: SettingsService.StorageKey, to data: Data?)
}Access Setting
Get & Set
let settings = SettingsService()
settings.set(.exampleNumber, to: 2)
let number = settings.get(.exampleNumber)Observable Value
value(_:) is @MainActor.
struct MyView: View {
let observableValue: SettingsService.Value<Int> = settings.value(.exampleNumber)
var body: some View {
Text("\(observableValue.value)")
SomeView(binding: observableValue.binding)
}
}Publisher
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).
Environment
The SettingsService can be injected via a SwiftUI environment key (@Entry on EnvironmentValues).
Inject into the @Environment:
View().environment(\.serviceSettings, settings)Read from @Environment:
@Environment(\.serviceSettings) private var settingsPackage Metadata
Repository: simonnickel/snap-settings-service
Default branch: main
README: README.md