I'm building a SwiftUI app with SwiftData and want to centralize both query logic and related actions in a manager class. For example, let's say I have a reading app where I need to track the currently reading book across multiple views.
What I want to achieve:
@Observable
class ReadingManager {
let modelContext: ModelContext
// Ideally, I'd love to do this:
@Query(filter: #Predicate<Book> { $0.isCurrentlyReading })
var currentBooks: [Book] // ❌ But @Query doesn't work here
var currentBook: Book? {
currentBooks.first
}
func startReading(_ book: Book) {
// Stop current book if any
if let current = currentBook {
current.isCurrentlyReading = false
}
book.isCurrentlyReading = true
try? modelContext.save()
}
func stopReading() {
currentBook?.isCurrentlyReading = false
try? modelContext.save()
}
}
// Then use it cleanly in any view:
struct BookRow: View {
@Environment(ReadingManager.self) var manager
let book: Book
var body: some View {
Text(book.title)
Button("Start Reading") {
manager.startReading(book)
}
if manager.currentBook == book {
Text("Currently Reading")
}
}
}
The problem is @Query only works in SwiftUI views. Without the manager, I'd need to duplicate the same query in every view just to call these common actions.
Is there a recommended pattern for this? Or should I just accept query duplication across views as the intended SwiftUI/SwiftData approach?