Using SwiftData and a shared SQLite database in an app and its share extension. If you merely tap Share in Safari, and the extension is shown, when you activate the app, one view throws:
DraftsView : getDrafts(): Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “default.store” couldn’t be opened." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/455BCEA6-209A-41EA-852D-0488375BD111/Library/Application Support/default.store, NSSQLiteErrorDomain=1}
error: -executeRequest: encountered exception = I/O error for database at /private/var/mobile/Containers/Shared/AppGroup/455BCEA6-209A-41EA-852D-0488375BD111/Library/Application Support/default.store. SQLite error code:1, 'no such table: ZDRAFT' with userInfo = { NSFilePath = "/private/var/mobile/Containers/Shared/AppGroup/455BCEA6-209A-41EA-852D-0488375BD111/Library/Application Support/default.store"; NSSQLiteErrorDomain = 1; }
None of that view's items are opened. Because the view saves the model context, all those items then appear permanently deleted.
The strange thing is the main view is unaffected.
To avoid concurrency issues, there are no @Query vars in either the app or the share extension, only fetches as needed.
SwiftData model for the view which fails:
@Model final class ClassA {
@Attribute(.unique)
var id: String
@Relationship(deleteRule: .cascade, inverse: \ClassB.parent)
var things: [ClassB] = [ClassB]()
}
@Model final class ClassB {
@Attribute(.unique)
var id: String
// Inverse link to parent
var parent: ClassA?
@Relationship(deleteRule: .cascade, inverse: \ClassC.parent)
var otherThings: [ClassC] = [ClassC]()
}
@Model final class ClassC {
@Attribute(.unique)
var id: String
// Inverse link to parent
var parent: ClassB?
}
For the view that's unaffected:
@Model final class Item {
@Attribute(.unique)
var id: UUID
var itemUrl: String
}
Share extension is all one Swift class:
class ShareViewController: SLComposeServiceViewController {
private let modelContainer: ModelContainer
private let modelContext: ModelContext
required init?(coder: NSCoder) {
do {
modelContainer = try ModelContainer(for: SavedItem.self, configurations: ModelConfiguration(isStoredInMemoryOnly: false))
} catch {
fatalError("Failed to create the model container: \(error)")
}
modelContext = modelContainer.mainContext
super.init(coder: coder)
}
[…]
func saveItem(itemUrl: String) {
var fetch = FetchDescriptor<Item>(
predicate: #Predicate { item in item.itemUrl == itemUrl }
)
fetch.includePendingChanges = true
let dupes = try? modelContext.fetch(fetch)
guard dupes?.count == 0 else { return }
let id = UUID()
let item = Item(id: id)
modelContext.insert(item)
do {
try modelContext.save()
} catch(let error) {
print("error: \(error.localizedDescription)")
}
}
}
Tried model actors, was a crashy hairball.
If you never view the share extension icon in Safari, app works fine.
Anyone have SwiftData share extension sample code that works?
Draft
that it is expecting to find in thedefault.store
. So it seems there is another container with other model types using the same store file as the extension is using for its singleSavedItem
model type.