Core Data Error After Recreating Persistant Store
Asked Answered
C

1

8

In my application, I have the ability to clear all data from the database. Once this operation completes, a bundled JSON is then parsed and then saved to the database (in order to return the database to the default state). The operation to parse and save this JSON works fine in any case except after clearing and recreating the persistant store, in which case I get 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'. This exception is thrown when trying to call mergeChangesFromContextDidSaveNotification on my main thread context after saving in a background context.

Recreating the store is performed on the main thread, where as parsing and saving always occurs on a background thread. Here is the getter for my managed object context to ensure thread-safeness:

- (NSManagedObjectContext *)managedObjectContext {

    NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
    NSManagedObjectContext *threadContext = threadDictionary[ckCoreDataThreadKey];

    if (!threadContext) {
        threadContext = [self newManagedObjectContext];
        threadDictionary[ckCoreDataThreadKey] = threadContext;
    }

    return threadContext;
}

the newManagedObjectContext method gives all new instances the same NSPersistentStoreCoordinator object.

Here is the code used to clear the store (performed on main thread always):

[self.managedObjectContext lock];
[self.managedObjectContext reset]; //to drop pending changes
                                       //delete the store from the current managedObjectContext
if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:error]) {
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:error];

    [[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:error]; //recreates the persistent store

    [self addSkipBackupAttributeToItemAtURL:storeURL];
}

[self.managedObjectContext unlock];

The strange part is that this same code works fine in other projects, and there are no differences other than the content of the data. Any help is greatly appreciated!

Crossarm answered 12/7, 2013 at 18:50 Comment(0)
V
13

The "Object's persistent store is not reachable from this NSManagedObjectContext's coordinator"

This message means you tried to use a managed object that was loaded from the data store that you just removed. You removed the persistent store from the coordinator and deleted the store file, but you still have at least one NSManagedObject that you loaded from that store. You can't use those objects any more, because if you do, you get this specific exception. Make sure you get rid of any existing managed objects before going nuclear on the Core Data stack in your second snippet.

As for why this works in a different app, most likely that app isn't holding on to stale managed objects.

Vasomotor answered 12/7, 2013 at 20:16 Comment(5)
indeed, you are right. the difference in this project and my others is that in this app, the root view controller manages a fetched results controller that is still holding objects when the store is removed. deleting and reloading that controller after the store is cleared and now it works great. thanks a million!Crossarm
Other possibility to get this error, if a temporaryContext - which parent is the crashing context - is in progress with a fetch request, setting values etc. and at the end temporaryContext wants to save back changes to the parent.Sidoon
any way to reload the app or all the views when this happens in swiftui?Gerianne
@Gerianne How to reload the entire UI is more of a SwiftUI question than a Core Data question. I have no idea, unfortunately.Vasomotor
For modern apps, the core data solution doesn’t work unless it’s possible to reload the views, which is why the error, or the next error people will get. The answer is you can’t. However you can get the sub views of the top level ContentView to be reloaded by putting a @State variable binded to a hidden Text view in the ContentView that is toggled by a notification. But before you do that you need to reset any contexts with context.reset(). This will effectively reload all data unless u are using core data objects from your App.swift - then you will have to manually reload each of those objsGerianne

© 2022 - 2024 — McMap. All rights reserved.