I'm getting an unusual unrecognized selector sent to instance
crash when trying to access a shared data controller object from inside an app shortcuts AppEntity
definition. It seems to relate to [NSCFString bytes]
.
The data controller is declared in my main app and passed through the environment:
struct myApp: App {
@StateObject var dataController: DataController
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(dataController)
}
}
init() {
_dataController = StateObject(wrappedValue: DataController.shared)
}
In my app entity and widgets, it is accessed as the shared instance. For example, here is an abridged version of the app entity and query.
struct MyAppEntity: AppEntity {
@Property(title: "Name")
var name: String?
// ... some code omitted
struct MyAppEntityQuery: EntityQuery {
// Option 1: Having data controller here flags a warning about it
// not being a Sendable type
let dataController = DataController.shared
func entities(for identifiers: [MyAppEntity.ID]) async throws -> [MyAppEntity] {
// Option 2: Having data controller here in the function is
// transient, so no Sendable warning as above
let dataController = DataController.shared
let items = dataController.getAllItems()
// ... use items to provide list for disambiguation
}
// ... some code omitted
}
}
Note the two options for location of the data controller. Both cause crashes, and using it as a top-level property raises a warning that it is not Sendable
like the rest of the struct
.
The problem is that the dataController.getAllItems()
method causes the crash when it in turn calls viewContext.fetch(Item.fetchRequest()
.
Behind the scenes, the getAllItems()
method does a Core Data fetch to return the items. The crash seems to happen (intermittently) if deleting or adding items, and sometimes on app startup (iOS seems to instantiate app entities at startup, so this code gets called). Interestingly, using the actual app shortcut works fine!
I had tried with the SwiftUI @FetchRequest
wrappers, like I use in the main app, but there is no managed object context
in the environment here.
I wonder if the Core Data stack is not ready in the shared instance when the App Entity code runs? Any advice would be appreciated.
One solution I'm considering is to save a lightweight representation of the data from Core Data as JSON and look this up to get the items for disambiguation. This is what I do for widgets as they are in an extension. I previously used an intent extension but this is iOS16 app shortcuts which (AFAIK) run in the main app process.
Edit
I was able to work around this by avoiding calling core data, and instead using the JSON-encoded data in the app group container that I already use for widgets. However that does not explain the issue here.