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()
}
mfaani
  • 33,269
  • 19
  • 164
  • 293
  • are you using multiple contexts? – Marcio Romero Patrnogic Dec 17 '18 at 21:21
  • 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... – mfaani Dec 17 '18 at 21:31
  • 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... – mfaani Dec 17 '18 at 21:51
  • I asked that but changed it as i wanted to get more context b4 asking xD... anyways.. glad u found the issue – Marcio Romero Patrnogic Dec 17 '18 at 22:09

1 Answers1

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])
mfaani
  • 33,269
  • 19
  • 164
  • 293
danh
  • 62,181
  • 10
  • 95
  • 136
  • 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. – mfaani Dec 17 '18 at 22:37
  • @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. – danh Dec 18 '18 at 00:22
  • _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? – mfaani Dec 18 '18 at 01:50
  • sorry, but can you take a look at my last comment? – mfaani Dec 20 '18 at 12:38
  • @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. – danh Dec 20 '18 at 15:36
  • @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. – danh Dec 20 '18 at 15:38
  • 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/different – mfaani Dec 20 '18 at 16:14
  • @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. – danh Dec 20 '18 at 16:19
  • 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. – mfaani Dec 20 '18 at 16:25
  • 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? – danh Dec 20 '18 at 18:28