Core Data
iOS development
data management
app development
Swift

Delete/Reset all entries in Core Data?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Deleting all entries in Core Data can be done with NSBatchDeleteRequest (fastest, bypasses object graph), fetch-and-delete loops (safe with relationships), or destroying the entire persistent store (nuclear reset). The right approach depends on your use case: batch delete for clearing specific entities, fetch-and-delete when cascade rules matter, and store destruction for a full factory reset. This article covers all three methods with Swift examples.

swift
1import CoreData
2
3func deleteAllEntities(_ entityName: String, context: NSManagedObjectContext) {
4    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
5    let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
6    batchDelete.resultType = .resultTypeObjectIDs
7
8    do {
9        let result = try context.execute(batchDelete) as? NSBatchDeleteResult
10        let objectIDs = result?.result as? [NSManagedObjectID] ?? []
11
12        // Merge changes into the in-memory context
13        let changes = [NSDeletedObjectsKey: objectIDs]
14        NSManagedObjectContext.mergeChanges(
15            fromRemoteContextSave: changes,
16            into: [context]
17        )
18        print("Deleted \(objectIDs.count) \(entityName) objects")
19    } catch {
20        print("Batch delete failed: \(error)")
21    }
22}
23
24// Usage
25deleteAllEntities("User", context: persistentContainer.viewContext)
26deleteAllEntities("Order", context: persistentContainer.viewContext)

NSBatchDeleteRequest operates directly on the persistent store, bypassing the managed object context. This makes it fast but requires merging changes back into the context to keep in-memory objects in sync.

Method 2: Delete All Entities in the Model

swift
1func deleteAllData(context: NSManagedObjectContext) {
2    let entityNames = context.persistentStoreCoordinator?.managedObjectModel.entities.compactMap { $0.name } ?? []
3
4    for entityName in entityNames {
5        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
6        let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
7
8        do {
9            try context.execute(batchDelete)
10        } catch {
11            print("Failed to delete \(entityName): \(error)")
12        }
13    }
14
15    // Save and reset the context
16    do {
17        try context.save()
18    } catch {
19        print("Save failed: \(error)")
20    }
21
22    context.reset()
23}

Iterating through all entities in the managed object model ensures everything is cleared without hardcoding entity names.

Method 3: Fetch and Delete (Relationship-Safe)

swift
1func fetchAndDeleteAll(_ entityName: String, context: NSManagedObjectContext) {
2    let fetchRequest: NSFetchRequest<NSManagedObject> = NSFetchRequest(entityName: entityName)
3
4    do {
5        let objects = try context.fetch(fetchRequest)
6        for object in objects {
7            context.delete(object)
8        }
9        try context.save()
10        print("Deleted \(objects.count) \(entityName) objects")
11    } catch {
12        print("Fetch and delete failed: \(error)")
13    }
14}

Fetch-and-delete loads objects into memory and deletes them one by one. This is slower than batch delete but respects cascade delete rules and triggers NSManagedObjectContextObjectsDidChange notifications.

Method 4: Destroy the Persistent Store (Full Reset)

swift
1func destroyPersistentStore(container: NSPersistentContainer) {
2    guard let storeURL = container.persistentStoreCoordinator
3        .persistentStores.first?.url else { return }
4
5    let coordinator = container.persistentStoreCoordinator
6
7    do {
8        // Destroy the store file
9        try coordinator.destroyPersistentStore(
10            at: storeURL,
11            ofType: NSSQLiteStoreType,
12            options: nil
13        )
14
15        // Recreate it empty
16        try coordinator.addPersistentStore(
17            ofType: NSSQLiteStoreType,
18            configurationName: nil,
19            at: storeURL,
20            options: nil
21        )
22        print("Store destroyed and recreated")
23    } catch {
24        print("Failed to reset store: \(error)")
25    }
26}

This deletes the SQLite file and recreates an empty one. It is the fastest way to reset everything but loses all data including metadata.

Method 5: Delete the SQLite File Directly

swift
1func deleteSQLiteFiles(container: NSPersistentContainer) {
2    guard let storeURL = container.persistentStoreCoordinator
3        .persistentStores.first?.url else { return }
4
5    let coordinator = container.persistentStoreCoordinator
6
7    // Remove the store from the coordinator first
8    for store in coordinator.persistentStores {
9        try? coordinator.remove(store)
10    }
11
12    // Delete all SQLite files
13    let fileManager = FileManager.default
14    let storePath = storeURL.path
15    let relatedFiles = [storePath, storePath + "-wal", storePath + "-shm"]
16
17    for file in relatedFiles {
18        try? fileManager.removeItem(atPath: file)
19    }
20
21    // Re-add the store
22    try? coordinator.addPersistentStore(
23        ofType: NSSQLiteStoreType,
24        configurationName: nil,
25        at: storeURL,
26        options: nil
27    )
28}

SQLite uses WAL (Write-Ahead Logging) files (-wal and -shm). Delete all three files to ensure a clean reset.

With Predicate (Conditional Delete)

swift
1// Delete only objects matching a condition
2func deleteWhere(_ entityName: String, predicate: NSPredicate, context: NSManagedObjectContext) {
3    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
4    fetchRequest.predicate = predicate
5
6    let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
7    try? context.execute(batchDelete)
8    try? context.save()
9}
10
11// Delete inactive users
12deleteWhere("User",
13    predicate: NSPredicate(format: "isActive == NO"),
14    context: viewContext
15)
16
17// Delete orders older than 30 days
18let thirtyDaysAgo = Calendar.current.date(byAdding: .day, value: -30, to: Date())!
19deleteWhere("Order",
20    predicate: NSPredicate(format: "createdAt < %@", thirtyDaysAgo as NSDate),
21    context: viewContext
22)

Common Pitfalls

  • Batch delete skips validation and cascade rules: NSBatchDeleteRequest operates on the SQLite store directly. It does not trigger cascade delete rules, validation, or willSave/didSave notifications. Use fetch-and-delete when relationships with cascade rules must be honored.
  • Stale objects in memory after batch delete: Objects loaded into the context before a batch delete become stale. Always merge changes with NSManagedObjectContext.mergeChanges(fromRemoteContextSave:into:) or call context.reset().
  • Forgetting WAL files: Deleting only the .sqlite file leaves -wal and -shm files, which can recreate the database with old data on next launch. Delete all three files.
  • Deleting on the wrong context: Perform deletes on a background context to avoid blocking the UI. Use container.newBackgroundContext() for heavy deletion operations.
  • Not saving after fetch-and-delete: context.delete(object) marks the object for deletion but does not persist the change. Call context.save() after all deletions to write changes to the store.

Summary

  • NSBatchDeleteRequest — fastest, operates on the store directly, requires manual context sync
  • Fetch-and-delete — slower but respects cascade rules and triggers notifications
  • destroyPersistentStore — nuclear option for full database reset
  • Delete with predicates for conditional clearing of specific records
  • Always merge batch delete changes into the context or call context.reset()
  • Delete all SQLite-related files (.sqlite, -wal, -shm) for a clean file-level reset

Course illustration
Course illustration

All Rights Reserved.