I have a pretty simple singleton that holds the SwiftData
modelContainer so that I can manipulate the DB a bit outside of the View but for some reason changes are not persisting.
import SwiftData
import SwiftUI
@Model
class Item {
var name: String
init(name: String) {
self.name = name
}
}
class DatabaseManager {
static let shared = DatabaseManager()
var modelContainer: ModelContainer {
do {
let container = try ModelContainer(for: Item.self)
return container
} catch {
fatalError("Unable to create ModelContainer: \(error)")
}
}
private init() {
print(modelContainer.configurations.first?.url.path ?? "No database file")
// Private initialization to ensure just one instance is created.
}
@MainActor func addItem() {
let item = Item(name: UUID().uuidString)
modelContainer.mainContext.insert(item)
}
@MainActor func itemCount() -> Int {
let fetchDescriptor = FetchDescriptor<Item>()
if let items = try? modelContainer.mainContext.fetch(fetchDescriptor) {
return items.count
}
return 0
}
}
I pass my modelContainer into my main window:
@main
struct testApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(DatabaseManager.shared.modelContainer)
}
}
Just as a test, all I do in my view is push the button to add an item and display the itemCount.
struct ContentView: View {
@State private var itemCount: Int = 0
var body: some View {
Button {
DatabaseManager.shared.addItem()
itemCount = DatabaseManager.shared.itemCount()
} label: {
Text("\(itemCount) Items")
}
}
}
The item count stays at zero no matter how many times I push the button
Exactly as @vadian said. As a test, try swapping this:
var modelContainer: ModelContainer {
do {
let container = try ModelContainer(for: Item.self)
return container
} catch {
fatalError("Unable to create ModelContainer: \(error)")
}
}
with this:
let modelContainer = try! ModelContainer(for: Item.self)
and see if it works.
Also, unrelated to your question but you can use @Query
to handle that itemCount
function in the view:
struct ContentView: View {
@Query var items: [Item]
var body: some View {
Button {
DatabaseManager.shared.addItem()
} label: {
Text("\(items.count) Items")
}
}
}