0

I am completely at this and out of ideas for about a week now.

I have a CoreData stack with multiple coordinators and managed contexts, and I am attempting to implement a logout feature in the app.

The tableviews that interact with CoreData is inside a TabBarController, and there are on-boarding (i.e. registration & login) NavigationControllers and ViewControllers that lead up to it.

What I am attempting to implement is a logout (i.e. unwind to initial ViewController. I have tried so far - to no avail:

  • reset() each managedObjectContext individually
  • every possible combination of tableView.beginUpdates(), tableView.endUpdates(), tableView.reloadData(), frc.performFetch()
  • Delete each entity in each managedObject then reset() each managedObjectContext individually
  • set tableView, fetchedResultsController delegates and datasource to nil, then to self on viewDidLoad()
  • Having a NSNotification that fires just before logging out - deleting everything in CoreData and saving it, effectively updating and emptying the table.
  • a whole lot more

Is there a way to completely reset CoreData so when the user unwinds to initial ViewController and re-run the whole process I won't get

Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. attempt to insert row 9 into section 0, but there are only 9 rows in section 0 after the update with userInfo (null)

or in the case I emptied the table via Notifications:

Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. attempt to insert row 9 into section 0, but there are only 0 rows in section 0 after the update with userInfo (null)

CoreData works just fine if I logout, close the app, and restart. No errors this way. This makes me think there is a way to completely reset CoreData (and any tableViews, fetchedResultsControllers associated with it) or reset to a pristine state when unwinding to the initial ViewController.

or should I just duplicate the storyboard and have a separate set of on-boarding viewControllers just for logging out so CoreData doesn't reinitialize?

Any ideas? Thanks.

William Yang
  • 759
  • 9
  • 30
  • Hii... I am clear lil bit about your problem , are you willing to reset core-data when you logout from app and when you login the whole process for core-data take place with initial level ? Am i assuming right ? – Anita Nagori Nov 28 '18 at 09:16
  • Did you try this link : https://stackoverflow.com/questions/24658641/ios-delete-all-core-data-swift – Anita Nagori Nov 28 '18 at 09:18
  • @Anita yes that is correct! I am looking to *completely* destroy and nuke CoreData if you will, not just individual entires. The tableviews somehow persists despite logout(unwind), batch delete requests, and context resets. – William Yang Nov 28 '18 at 09:28
  • Please check this link : https://stackoverflow.com/questions/1383598/core-data-quickest-way-to-delete-all-instances-of-an-entity – Anita Nagori Nov 28 '18 at 09:32
  • Above link might helpful to you – Anita Nagori Nov 28 '18 at 09:32
  • @Anita I checked and no it didn't. Does not work. I have tried NSBatchDeleteRequest many times and it's still giving me the same error. Restarting the app works fine tho. – William Yang Nov 28 '18 at 09:40
  • Do you have any sample project ? If yes then you can share will try it out at my side – Anita Nagori Nov 28 '18 at 09:42

2 Answers2

2

In iOS9 and above you can use destroyPersistentStore and optionally add a new one

func destroyAllData(storeType : String = NSSQLiteStoreType) throws {
    guard let storeURL = persistentStoreCoordinator.persistentStores.last?.url else {
        print("Missing store URL")
        return
    }
    try persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: storeType)
    // try persistentStoreCoordinator.addPersistentStore(ofType: storeType, configurationName: nil, at: storeURL)
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thank lord you're a savior! Extended this to work on multiple stores/coordinators, re-add the sqlite stores and it worked like magic! Why I haven't realized this is beyond disbelief! – William Yang Nov 28 '18 at 18:02
0

try this!

  static let moduleName = "moduleName"

        //Model
        lazy var managedObjectModel:NSManagedObjectModel = {
            let modelURL = Bundle.main.url(forResource: moduleName, withExtension: "momd")!
            return NSManagedObjectModel(contentsOf: modelURL)!
        }()

     func deleteAllEntities() {
            let entities = managedObjectModel.entities
            for entity in entities {
                delete(entityName: entity.name!)
            }
        }

func delete(entityName: String) {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try persistentStoreCoordinator.execute(deleteRequest, with: DataCoordinator.shared.managedObjectContext)
            debugPrint("Deleted Entitie - ", entityName)
        } catch let error as NSError {
            debugPrint("Delete ERROR \(entityName)")
            debugPrint(error)
        }
    }