Why entries are not deleted until app is restarted or I execute my NSBatchDeleteRequest twice?
Asked Answered
S

1

3

I'm reading Delete/Reset all entries in Core Data?.

If I follow the steps below, I get an unexpected result:

  1. Call the code below
  2. Then query an entity in the simulator, I will get an entity back!!!
  3. If I call clearCoreDataStore again (or do a restart), only then the value won't be retrieved from core-data

What am I missing?

func clearCoreDataStore() {
    let entities = dataManager.persistentContainer.managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.execute(deleteReqest)
        } catch {
            print(error)
        }
    }
    dataManager.saveContext()
}
Switchboard answered 17/12, 2018 at 21:15 Comment(4)
are you using multiple contexts?Jaco
This is a dummy app. It's a single viewController that has a single persistentContainer property. All operations are using the context of the persistentContainer property...Switchboard
I've made an edit. I was forgetting to do saveContext. Yet if I call my clearCoreDataStore and query ... I will get a result back. But if I call again, then nothing would be returned. Not sure why I need to do it twice...Switchboard
I asked that but changed it as i wanted to get more context b4 asking xD... anyways.. glad u found the issueJaco
K
7

The objects being deleted from the persistent store are probably also in an in-memory object context. If so, that memory context must first be updated to reflect the deletions. A thorough discussion can be found here.

In a nutshell...

deleteRequest.resultType = NSBatchDeleteRequestResultType.resultTypeObjectIDs
let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
let objectIDArray = result?.result as? [NSManagedObjectID]
let changes = [NSDeletedObjectsKey : objectIDArray]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
Kielty answered 17/12, 2018 at 22:14 Comment(10)
Makes sense. I tried your suggestion and it correctly deletes on the first attempt and no restart is required. This certainly does explain why I needed to restart the app. Does this also explain why I needed to do my NSBatchDeleteRequest twice to work? I've made edit in the question to clarify what issue I'm facing.Switchboard
@Honey, yes it explains both modes of behavior. Using main queue concurrency, the sync happens after your app returns from the main run loop. The reason the first query shows stale data is that your app hasn't returned yet (on the current run loop iteration). The second query happens after everything is sync'd again.Kielty
The reason the first query shows stale data is that your app hasn't returned yet (on the current run loop iteration) what?! it's not like I'm calling it in a split second...I query it 5 seconds later...and still it's being retrieved. Am I missing something?Switchboard
sorry, but can you take a look at my last comment?Switchboard
@Honey - sorry I missed it. After some research I don't find anything authoritative that sets out when the in-memory context is certain to be updated passively. My incorrect assumption was the behavior is analogous to NSUserDefaults but you've discovered evidence to the contrary. The only reason I can imagine caring about this is if I'm going to build logic that depends on this vague (and apparently undocumented) behavior. I would advise against that. Even if you find a repeatably working pattern, you risk being undone by an OS change.Kielty
@Honey - In other words, my advice for an app that depends on the in-memory context being up-to-date immediately after a delete, must force a sync manually.Kielty
Thank you so much for your time. Just that did you verify the observer the behavior yourself too? I mean I could be doing something wrong. Core-data is new to me and I could have setup something wrong/differentSwitchboard
@Honey - I didn't, but the behavior you're seeing is consistent with expectations, including the idea that the memory context is updated asynchronously. The only thing we're stuck with is some non-determinism in that behavior. But that's only a problem if we expect determinism, and the docs give us no reason to.Kielty
Let's assume it's updated asynchronously. Isn't 10 seconds enough for it to be do this delete? My setup is super simple I just like 2 entries. It's a dummy project.Switchboard
We can't reason about logic that's hidden from us. If the logic is to sync before tearing down the doc, then no amount of time will be enough. What's wrong with telling the MOC to sync when you want it to sync?Kielty

© 2022 - 2024 — McMap. All rights reserved.