I am encountering an issue when attempting to share the same ModelContainer
instance between two separate targets: App
and WidgetBundle
. To achieve this, I created a StorageController
to manage the ModelContainer
and injected it into both targets.
<code>// StorageController.swift
public static var globalInstance: StorageController = StorageController()
let modelContainer: ModelContainer
let modelContext: ModelContext
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
modelContainer = try ModelContainer(for: schema, configurations: config)
modelContext = modelContainer.mainContext
Logger().info("init modelContainer")
guard let urlApp = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).last else { return }
let url = urlApp.appendingPathComponent("default.store")
if FileManager.default.fileExists(atPath: url.path) {
Logger().info("swiftdata db at (url.absoluteString)")
Logger().warning("can't find swiftdata db")
fatalError("Could not initialize ModelContainer")
// MyWidgetExtentionBundle.swift
struct MyWidgetExtentionBundle: WidgetBundle {
Logger().info("MyWidgetExtentionBundle init")
let sc = StorageController.globalInstance
AppDependencyManager.shared.add(dependency: sc)
// AppIntentsInWidgetExtentionApp.swift
struct AppIntentsInWidgetExtentionApp: App {
private var storageController: StorageController
let sc = StorageController.globalInstance
Text("Total item cnt:(storageController.fetchItems().count)")
storageController.addItem(name: "Item-(UUID().uuidString)")
<code>// StorageController.swift
@MainActor
public static var globalInstance: StorageController = StorageController()
let modelContainer: ModelContainer
let modelContext: ModelContext
@MainActor
init() {
do {
let schema = Schema([
Item.self,
])
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
modelContainer = try ModelContainer(for: schema, configurations: config)
modelContext = modelContainer.mainContext
Logger().info("init modelContainer")
guard let urlApp = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).last else { return }
let url = urlApp.appendingPathComponent("default.store")
if FileManager.default.fileExists(atPath: url.path) {
Logger().info("swiftdata db at (url.absoluteString)")
} else {
Logger().warning("can't find swiftdata db")
}
} catch {
fatalError("Could not initialize ModelContainer")
}
}
// MyWidgetExtentionBundle.swift
@main
struct MyWidgetExtentionBundle: WidgetBundle {
@MainActor
init() {
Logger().info("MyWidgetExtentionBundle init")
let sc = StorageController.globalInstance
AppDependencyManager.shared.add(dependency: sc)
}
var body: some Widget {
MyWidgetExtention()
}
}
// AppIntentsInWidgetExtentionApp.swift
@main
struct AppIntentsInWidgetExtentionApp: App {
@State
private var storageController: StorageController
init() {
let sc = StorageController.globalInstance
storageController = sc
}
var body: some Scene {
WindowGroup {
VStack {
Text("Total item cnt:(storageController.fetchItems().count)")
Button("Add Item") {
storageController.addItem(name: "Item-(UUID().uuidString)")
}
}
}
}
}
</code>
// StorageController.swift
@MainActor
public static var globalInstance: StorageController = StorageController()
let modelContainer: ModelContainer
let modelContext: ModelContext
@MainActor
init() {
do {
let schema = Schema([
Item.self,
])
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
modelContainer = try ModelContainer(for: schema, configurations: config)
modelContext = modelContainer.mainContext
Logger().info("init modelContainer")
guard let urlApp = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).last else { return }
let url = urlApp.appendingPathComponent("default.store")
if FileManager.default.fileExists(atPath: url.path) {
Logger().info("swiftdata db at (url.absoluteString)")
} else {
Logger().warning("can't find swiftdata db")
}
} catch {
fatalError("Could not initialize ModelContainer")
}
}
// MyWidgetExtentionBundle.swift
@main
struct MyWidgetExtentionBundle: WidgetBundle {
@MainActor
init() {
Logger().info("MyWidgetExtentionBundle init")
let sc = StorageController.globalInstance
AppDependencyManager.shared.add(dependency: sc)
}
var body: some Widget {
MyWidgetExtention()
}
}
// AppIntentsInWidgetExtentionApp.swift
@main
struct AppIntentsInWidgetExtentionApp: App {
@State
private var storageController: StorageController
init() {
let sc = StorageController.globalInstance
storageController = sc
}
var body: some Scene {
WindowGroup {
VStack {
Text("Total item cnt:(storageController.fetchItems().count)")
Button("Add Item") {
storageController.addItem(name: "Item-(UUID().uuidString)")
}
}
}
}
}
However, after adding logging to verify the location of the ModelContainer
store file, I found that two different default.store
files are being created.
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Library/Application%20Support/default.store
# start with WidgetBundle
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Containers/Data/Application/7465C92B-AC5A-4AB0-BA68-2EEB78C16A38/Library/Application%20Support/default.store
<code># start with App
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Library/Application%20Support/default.store
# start with WidgetBundle
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Containers/Data/Application/7465C92B-AC5A-4AB0-BA68-2EEB78C16A38/Library/Application%20Support/default.store
</code>
# start with App
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Library/Application%20Support/default.store
# start with WidgetBundle
swiftdata db at file:///Users/username/Library/Developer/CoreSimulator/Devices/99106351-788D-4605-A5E6-475AD73ED05C/data/Containers/Data/Application/7465C92B-AC5A-4AB0-BA68-2EEB78C16A38/Library/Application%20Support/default.store
What is the correct approach to ensure that the ModelContainer
is shared between the App
and WidgetBundle
targets, so that data remains synchronized?