Sharing
Instantly share state among your app’s features and external persistence layers, including user defaults, the file system, and more.
import Sharing
Module information
- Declarations
- 173
- Symbols
- 273
Additional Resources
Overview
This library comes with a few tools that allow one to share state with multiple parts of your application, as well as external store systems such as user defaults, the file system, and more. The tool works in a variety of contexts, such as SwiftUI views, @Observable
models, and UIKit view controllers, and it is completely unit testable.
As a simple example, you can have two different obsevable models hold onto a collection of data that is also synchronized to the file system:
// MeetingsList.swift
@Observable
class MeetingsListModel {
@ObservationIgnored
@Shared(.fileStorage(.meetingsURL)) var meetings: [Meeting] = []
}
// ArchivedMeetings.swift
@Observable
class ArchivedMeetingsModel {
@ObservationIgnored
@Shared(.fileStorage(.meetingsURL)) var meetings: [Meeting] = []
}
If either model makes a change to meetings
, the other model will instantly see those changes. And further, if the file on disk changes from an external write, both instances of @Shared
will also update to hold the freshest data.
Automatic persistence
The @Shared
property wrapper gives you a succinct and consistent way to persist any kind of data in your application. The library comes with 3 strategies: appStorage
, fileStorage
, and inMemory
.
The appStorage
strategy is useful for store small pieces of simple data in user defaults, such as settings:
@Shared(.appStorage("soundsOn")) var soundsOn = true
@Shared(.appStorage("hapticsOn")) var hapticsOn = true
@Shared(.appStorage("userSort")) var userSort = UserSort.name
The fileStorage
strategy is useful for persisting more complex data types to the file system by serializing the data to bytes:
@Shared(.fileStorage(.meetingsURL)) var meetings: [Meeting] = []
And the inMemory
strategy is useful for sharing any kind of data globably with the entire app, but it will be reset the next time the app is relaunched:
@Shared(.inMemory("events")) var events: [String] = []
See Persistence strategies for more information on leveraging the persistence strategies that come with the library, as well as creating your own strategies.
Use anywhere
It is possible to use @Shared
state essentially anywhere, including observable models, SwiftUI views, UIKit view controllers, and more. For example, if you have a simple view that needs access to some shared state but does not need the full power of an observable model, then you can use @Shared
directly in the view:
struct DebugMeetingsView: View {
@Shared(.fileStorage(.meetingsURL)) var meetings: [Meeting] = []
var body: some View {
ForEach(meetings) { meeting in
Text(meeting.title)
}
}
}
Similarly, if you need to use UIKit for a particular feature or have a legacy feature that can’t use SwiftUI yet, then you can use @Shared
directly in a view controller:
final class DebugMeetingsViewController: UIViewController {
@Shared(.fileStorage(.meetingsURL)) var meetings: [Meeting] = []
// ...
}
And to observe changes to meetings
so that you can update the UI you can either use the publisher
property or the observe
tool from our Swift Navigation library. See Observing changes to shared state for more information.
Testing shared state
Features using the @Shared
property wrapper remain testable even though they interact with outside storage systems, such as user defaults and the file system. This is possible because each test gets a fresh storage system that is quarantined to only that test, and so any changes made to it will only be seen by that test.
See Testing for more information on how to test your features when using @Shared
.
Demos
The Sharing repo comes with lots of examples to demonstrate how to solve common and complex problems with @Shared
. Check out this directory to see them all, including:
Case Studies: A number of case studies demonstrating the built-in features of the library.
FirebaseDemo: A demo showing how shared state can be powered by a remote Firebase config.
GRDBDemo: A demo showing how shared state can be powered by SQLite in much the same way a view can be powered by SwiftData’s
@Query
property wrapper using GRDB..WasmDemo: A SwiftWasm application that uses this library to share state with your web browser’s local storage.
SyncUps: We also rebuilt Apple’s Scrumdinger demo application using modern, best practices for SwiftUI development, including using this library to share state and persist it to the file system.
Essentials
struct Shared<Value>
A property wrapper type that shares a value with other parts of the application and/or external systems.
struct SharedReader<Value>
A property wrapper type that shares a read-only value with multiple parts of an application.
Persistence strategies
Learn about the various persistence strategies that ship with the library, as well as how to create your own custom strategies.
Read MoreMutating shared state
Learn how to mutate shared state in a safe manner in order to prevent race conditions and data loss.
Read MoreObserving changes to shared state
Learn how to observe changes to shared state in order to update your UI or react to changes.
Read MoreDeriving shared state
Learn how to derive shared state to sub-parts of a larger piece of shared state.
Read MoreReusable, type-safe keys
Learn how to define keys for your shared state that allow you to reference your data in a statically checked and type-safe manner.
Read MoreInitialization rules
Learn the various ways to initialize shared state, both when using a persistence strategy and when not.
Read MoreTesting
Learn how to test features that use shared state, even when persistence strategies are involved.
Read MoreGotchas of @Shared
Learn about a few gotchas to be aware of when using shared state in your application.
Read More
Persistence
struct AppStorageKey<Value>
A type defining a user defaults persistence strategy.
class FileStorageKey<Value>
A type defining a file persistence strategy
struct InMemoryKey<Value>
A type defining an in-memory persistence strategy
typealias Default
Provides a default value to a shared key.
Custom persistence
protocol SharedKey<Value>
A type that can persist shared state to an external storage.
protocol SharedReaderKey<Value>
A type that can load and subscribe to state in an external system.
Migration guides
Migration guides
Learn how to upgrade your application to the newest version of Sharing.
Read More