0
votes

I have a SwiftUI View struct to which I pass a Place object in the init function. Using an id I want to load a corresponding UserPlaceInfo from CoreData. Unfortunately my app crashes when I try to access the fetchedResults in the init function. If I use the same code in onAppear this works without problems.

private var fetchRequest : FetchRequest <UserPlaceInfo>
private var fetchedResults: FetchedResults<UserPlaceInfo> { fetchRequest.wrappedValue }

init(place : Place) {
    self.place = place
    fetchRequest = FetchRequest<UserPlaceInfo>(entity : UserPlaceInfo.entity(), sortDescriptors : [] , predicate: NSPredicate(format: "id == %@", place.id))
    // Application crashes here!
    let count = fetchedResults.count
}

Why is that and what can I do about it? Am I doing something wrong or are the fetchedResults not yet available at this time? I need the result very early, because if there is no UserPlaceInfo in CoreData, I have to create such an object.

UPDATE

Adding fetchRequest.update() helped a bit. Now I am getting a more useful error message: Context in environment is not connected to a persistent store coordinator

I still don't understand what is going on. I add the managedObjectContext to the environment in the SceneDelegate and the fetch works fine if I do it in onAppear.

1
Try to use fetchRequest.update() before fetchedResults usage - Asperi
which error message is displayed in the crashlog? - Chris
Is this MacOS or iOS? The last error looks like the issue with the persistent store coordinator not being loaded yet on MacOS. Removing lazy for var persistentContainer in the AppDelegate or making sure it gets initialised before the ContentView is created is a solution. - Joakim Danielson
@JoakimDanielson It is iOS but still in the simulator. Removing lazy did not help. - TalkingCode

1 Answers

2
votes

I just ran into this same issue, you've probably gotten it to work by now, but I figured I'd help someone out if they encounter this in the future. You won't have access to the managedObjectContext in init. Instead, what you'll want to do is create a separate method and call that on appear. Modify your code like so.

init(place : Place) {
    self.place = place
    fetchRequest = FetchRequest<UserPlaceInfo>(entity : UserPlaceInfo.entity(), sortDescriptors : [] , predicate: NSPredicate(format: "id == %@", place.id))
}

And then in your body, you do something like this

var body: some View {        
  VStack {
    .. your views here
  }.onAppear(perform: onLoad) // the magic!        
}

And finally

func onLoad() 
{
    print(fetchedResults.count) // it should work now
}