Search code examples
swiftuicore-dataswiftui-list

Why does a pre-configured @FetchRequest not update the SwiftUI view?


Whenever I am using a pre-configured NSFetchRequest like so:

extension Note {
    static var requestPrivateDBNotesByDate: NSFetchRequest<Note> {
        let request = Note.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(keyPath: \Note.createdDate, ascending: true)]
        request.affectedStores = [PersistenceController.shared.privatePersistentStore]
        return request
}

to do a @FetchRequest within a SwiftUI view:

@FetchRequest(fetchRequest: Note.requestPrivateDBNotesByDate)
private var notes: FetchedResults<Note>

the SwiftUI view is not updating when I add a Note entity to CoreData:

func addNote(name: String, context: NSManagedObjectContext) {
    context.perform {
        let note = Note(context: context)
        note.displayName = name
        note.createdDate = .now
        try? context.save()
    }
}

If I use a simple @FetchRequest within my SwiftUI view like so:

@FetchRequest(sortDescriptors: [SortDescriptor(\.displayName, order: .forward)]
) private var notes: FetchedResults<Note>

the view updates whenever I add a now Note.

Why is the pre-configured @FetchRequest not updating my SwiftUI view?

Note: I can force a view update by adding context.refresh(chat, mergeChanges: false) after context.save() but then my question would be, why do I need to force a refresh with a pre-configured @FetchRequest while it is not necessary with a simple @FetchRequest.

Is the forced refresh the only/correct way to go? Am I missing something?

Update:

This is how I get the privatePersistentStore for the affectedStores property in the pre-configured NSFetchRequest.

var privatePersistentStore: NSPersistentStore {
    var privateStore: NSPersistentStore?
    let descriptions = persistentContainer.persistentStoreDescriptions
    
    for description in descriptions {
        if description.cloudKitContainerOptions?.databaseScope == .private {
            guard let url = description.url else { fatalError("NO STORE URL!") }
            guard let store = persistentContainer.persistentStoreCoordinator.persistentStore(for: url) else { fatalError("NO STORE!") }
            privateStore = store
        }
    }
    guard let privateStore else { fatalError("NO PRIVATE STORE!") }
    return privateStore
}

Solution

  • you forgot to assign the new note to the store you are fetching from, e.g.

    context.assign(to: PersistenceController.shared.privatePersistentStore)
    try? context.save()