Lets say you have a SwiftUI app, like the landmarks app, that currently has single Observable class instance in charge of providing data for the whole app:
@Observable
class ModelData {
var landmarks: [Landmark] = load("landmarkData.json")
var hikes: [Hike] = load("hikeData.json")
var profile = Profile.default
var features: [Landmark] {
landmarks.filter { $0.isFeatured }
}
var categories: [String: [Landmark]] {
Dictionary(
grouping: landmarks,
by: { $0.category.rawValue }
)
}
}
It is provided to the app like this:
@main
struct LandmarksApp: App {
@State private var modelData = ModelData()
var body: some Scene {
WindowGroup {
ContentView()
.environment(modelData)
}
}
}
And accessed within individual components of the app like this:
@Environment(ModelData.self) var modelData
If we were to convert this app to SwiftData, we could:
A) Model the Landmark and Hike objects separately by putting “@Model” on each one… and getting rid of the computed queries and using @Query instead. (Not sure what we would do with Profile since it is singular)… and share those two separate “model arrays” (?) with the rest of the app using the technique in this question. In this case, the ModelData class would no longer exist.
B) OR…. (this is the question)… can we just put an SwiftData “@Model” on the existing ModelData class as a whole, and share it with the entire app? I’ve started trying to do this, and I have got as far as
@Model
class ModelData {
var landmarks: [Landmark]
var hikes: [Hike]
var profile: Profile
var features: [Landmark] {
landmarks.filter { $0.isFeatured }
}
var categories: [String: [Landmark]] {
Dictionary(
grouping: landmarks,
by: { $0.category.rawValue }
)
}
init(landmarks: [Landmark] = load("landmarks.json"), hikes: [Hike] = load("hikes.json"), profile:Profile = Profile.default) {
self.landmarks = landmarks
self.hikes = hikes
self.profile = profile
}
}
… and it compiles since I made everything codable… but when I start thinking about how I would edit or update landmarks my head hurts… and it seems like maybe it’s never a good idea to use this “option B.”
However, when I proceed with option A, I reach a point where I realize I have lost the utility functions and they will have to be scattered in the codebase.
Are these equally valid approaches?




