How to use SwiftData to store singletons
How to use SwiftData to store singletons 관련
Updated for Xcode 15
Given how easy SwiftData makes data storage, you’re likely to be tempted to want to use it for general app storage such as settings and more. However, this takes a little more work because the @Query
macro is designed to return collections of model objects rather than a single instance.
They here is to create a custom fetch request to read the whole collection of results, then simply return the first one to get your data, or create a fresh instance if there was nothing already saved.
As an example, we might have an AppSettings
model such as this one:
@Model class AppSettings {
var name: String
var location: String
var selectedTopics: [String]
init(name: String, location: String, selectedTopics: [String]) {
self.name = name
self.location = location
self.selectedTopics = selectedTopics
}
}
We could then load that either at app launch, or using onAppear()
inside a root view such as this:
struct ContentView: View {
@Environment(\.modelContext) var modelContext
@State private var settings: AppSettings?
var body: some View {
NavigationStack {
VStack {
if let settings {
Text("Name: \(settings.name)")
Text("Location: \(settings.location)")
Text("Topics: \(settings.selectedTopics.formatted(.list(type: .and)))")
} else {
Text("Loading…")
}
}
.navigationTitle("Singletons")
.onAppear(perform: load)
}
}
func load() {
let request = FetchDescriptor<AppSettings>()
let data = try? modelContext.fetch(request)
settings = data?.first ?? AppSettings(name: "Anonymous", location: "Unknown", selectedTopics: ["Latest News"])
}
}
While this approach definitely works, it’s worth asking whether it’s the best option – would using a simple Codable
type work better, for example?
Note
Although SwiftData supports working with document-based apps, it does not provide the document as a singleton inside there – you still need to issue a query for a collection of results.