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.
Method 1: NSBatchDeleteRequest (Recommended)
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
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)
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)
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
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)
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