webentwicklung-frage-antwort-db.com.de

Kerndaten: Der schnellste Weg zum Löschen aller Instanzen einer Entität

Ich verwende Core Data, um Ergebnisse eines Web Services-Aufrufs lokal zu speichern. Der Webservice gibt das vollständige Objektmodell für beispielsweise "Autos" zurück - es könnten etwa 2000 davon sein (und ich kann den Webservice nicht dazu veranlassen, weniger als 1 oder ALLE Autos zurückzugeben.).

Wenn ich das nächste Mal meine Anwendung öffne, möchte ich die persistente Core Data-Kopie aktualisieren, indem der Web-Service erneut für alle Autos aufgerufen wird. Um Doppelarbeit zu vermeiden, müsste ich jedoch zuerst alle Daten im lokalen Cache löschen.

Gibt es eine schnellere Methode, ALLE Instanzen einer bestimmten Entität im Kontext des verwalteten Objekts zu löschen (z. B. alle Entitäten vom Typ "CAR"), oder muss ich den Aufruf abfragen, dann die Ergebnisse durchlaufen, um sie zu löschen, und dann speichern?

Idealerweise könnte ich einfach sagen, dass alles gelöscht werden soll, wo die Entität Blah ist.

359
Adaromas

iOS 9 und höher:

iOS 9 fügte eine neue Klasse mit dem Namen NSBatchDeleteRequest hinzu, mit der Sie Objekte, die einem Prädikat entsprechen, problemlos löschen können, ohne sie alle in den Speicher laden zu müssen. So verwenden Sie es:

Schnell 2

let fetchRequest = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try myPersistentStoreCoordinator.executeRequest(deleteRequest, withContext: myContext)
} catch let error as NSError {
    // TODO: handle the error
}

Ziel c

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"];
NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

NSError *deleteError = nil;
[myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError];

Weitere Informationen zu Batch-Löschungen finden Sie in der Sitzung "Was ist neu in Core Data" ab WWDC 2015 (ab ~ 14: 10).

iOS 8 und früher:

Hol 'sie alle und lösche sie alle:

NSFetchRequest *allCars = [[NSFetchRequest alloc] init];
[allCars setEntity:[NSEntityDescription entityForName:@"Car" inManagedObjectContext:myContext]];
[allCars setIncludesPropertyValues:NO]; //only fetch the managedObjectID

NSError *error = nil;
NSArray *cars = [myContext executeFetchRequest:allCars error:&error];
[allCars release];
//error handling goes here
for (NSManagedObject *car in cars) {
  [myContext deleteObject:car];
}
NSError *saveError = nil;
[myContext save:&saveError];
//more error handling here
685
Dave DeLong

Etwas sauberer und universeller: Fügen Sie diese Methode hinzu:

- (void)deleteAllEntities:(NSString *)nameEntity
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:nameEntity];
    [fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID

    NSError *error;
    NSArray *fetchedObjects = [theContext executeFetchRequest:fetchRequest error:&error];
    for (NSManagedObject *object in fetchedObjects)
    {
        [theContext deleteObject:object];
    }

    error = nil;
    [theContext save:&error];
}
31
Numereyes

Entität in Swift 3 zurücksetzen

func resetAllRecords(in entity : String) // entity = Your_Entity_Name
    {

        let context = ( UIApplication.shared.delegate as! AppDelegate ).persistentContainer.viewContext
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
        do
        {
            try context.execute(deleteRequest)
            try context.save()
        }
        catch
        {
            print ("There was an error")
        }
    }
27
roy

Für Swift 2.0:

class func clearCoreData(entity:String) {
  let fetchRequest = NSFetchRequest()
  fetchRequest.entity = NSEntityDescription.entityForName(entity, inManagedObjectContext: moc!)
  fetchRequest.includesPropertyValues = false
  do {
    if let results = try moc!.executeFetchRequest(fetchRequest) as? [NSManagedObject] {
      for result in results {
        moc!.deleteObject(result)
      }

      try moc!.save()
    }
  } catch {
    LOG.debug("failed to clear core data")
  }
}
16
Gaurav Sharma

Swift:

let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
fetchRequest.includesPropertyValues = false

var error:NSError?
if let results = context.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject] {
    for result in results {
        context.deleteObject(result)
    }

    var error:NSError?
    if context.save(&error) {
        // do something after save

    } else if let error = error {
        println(error.userInfo)
    }

} else if let error = error {
    println("error: \(error)")
}
12
Ixx

Dies ist eine ähnliche Frage wie hier , und jemand schlug vor, eine Beziehungslöschregel einzurichten, sodass Sie nur ein Objekt löschen müssen. Wenn Sie also eine Entität mit einer zu vielen Beziehung zu den Autos haben oder herstellen können und die Löschregel auf Kaskade setzen, wenn Sie die höhere Entität löschen, werden auch alle Autos gelöscht. Dies kann einige Bearbeitungszeit einsparen, da Sie nicht alle Schritte zum Beladen ALLER Fahrzeuge durchführen müssen. In einem größeren Datensatz könnte dies absolut notwendig sein. 

9
T. Markle

Eine gute Antwort wurde bereits gepostet, dies ist nur eine Empfehlung!

Ein guter Weg wäre, einfach eine Kategorie zu NSManagedObject hinzuzufügen und eine Methode wie ich zu implementieren:

Header-Datei (z. B. NSManagedObject+Ext.h)

@interface NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString*) entityName;

@end

Codedatei: (z. B. NSManagedObject + Ext.m)

@implementation NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString *)entityName {
    NSManagedObjectContext *managedObjectContext = [AppDelegate managedObjectContext];
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [managedObjectContext executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [managedObjectContext deleteObject:profile];
    }
    NSError *saveError = nil;
    [managedObjectContext save:&saveError];
}

@end

... das einzige, was Sie tun müssen, ist den managedObjectContext von dem App-Delegaten zu erhalten, oder wo Sie ihn alle haben;)

danach kannst du es wie folgt verwenden:

[NSManagedObject deleteAllFromEntity:@"EntityName"];

eine weitere Optimierung könnte darin bestehen, dass Sie den Parameter für den Entitätsnamen entfernen und stattdessen den Namen aus dem Clazznamen abrufen. Dies würde zur Verwendung führen:

[ClazzName deleteAllFromEntity];

ein saubereres impl (als Kategorie zu NSManagedObjectContext):

@implementation NSManagedObjectContext (Logic)

- (void) deleteAllFromEntity:(NSString *)entityName {
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:self]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [self executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [self deleteObject:profile];
    }
    NSError *saveError = nil;
    [self save:&saveError];
}

@end

Die Verwendung dann:

[managedObjectContext deleteAllFromEntity:@"EntityName"];
8
Erhard Dinhobl

iOS 10 und höher

Funktioniert mit allen Versionen. Übergeben Sie den Entitätsnamen und iterieren Sie, um alle Einträge zu löschen und den Kontext zu speichern.

func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
        let context = NSManagedObjectContext()
        context = your managedObjectContext

        let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
        fetchRequest.entity = NSEntityDescription.entity(forEntityName: entityToFetch, in: context)
        fetchRequest.includesPropertyValues = false
         do {   
            let results = try context.fetch(fetchRequest) as! [NSManagedObject]
            for result in results {
                context.delete(result)
            }
            try context.save()
            completion(true)
        } catch {
            completion(false)
            print("fetch error -\(error.localizedDescription)")
        }
    }
4
Karun Kumar

Dave Delongs Antwort erweitern.

Swift-Version, die auch iOS 9 und frühere Versionen berücksichtigt. Ich habe auch die Fehlerbehandlung behandelt:

lassen Sie appDelegate: AppDelegate = UIApplication.sharedApplication (). als delegieren! AppDelegate

    let fetchRequest = NSFetchRequest(entityName: "Car")
    if #available(iOS 9.0, *) {
        let delete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try appDelegate.persistentStoreCoordinator.executeRequest(delete, withContext: appDelegate.managedObjectContext)
        } catch let error as NSError {
            print("Error occured while deleting: \(error)")
        }
    } else {
        // Fallback on earlier versions
        let carRequest = NSFetchRequest()
        carRequest.entity = NSEntityDescription.entityForName("Cars", inManagedObjectContext: appDelegate.managedObjectContext)
        carRequest.includesPropertyValues = false

        do {
            let cars: NSArray = try appDelegate.managedObjectContext.executeFetchRequest(carRequest)

            for car in cars {
                appDelegate.managedObjectContext.delete(car)
            }

            try appDelegate.managedObjectContext.save()

        } catch let error as NSError {
            print("Error occured while fetching or saving: \(error)")
        }
    }
4
Maheen Khalid

Swift 3.X und Swift 4.X , Einfache Möglichkeit. Nur ändern YourTable

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "YourTable")
    fetchRequest.returnsObjectsAsFaults = false

    do
    {
        let results = try context.fetch(fetchRequest)
        for managedObject in results
        {
            let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
            context.delete(managedObjectData)
        }
    } catch let error as NSError {
        print("Detele all my data in \(entity) error : \(error) \(error.userInfo)")
    }
3
SwiftDeveloper

Swift 4, iOS 12 und Xcode 10 Update

100% arbeiten nur schneiden und einfügen

Setzen Sie diese Funktion einfach in die relevante Klasse
und rufen Sie diese Funktion self.deleteData() in viewDidLoad() .__ auf.

oder an einer beliebigen Stelle oder unter einer Funktion oder einer Schaltfläche, sodass durch Klicken auf eine Schaltfläche alle Daten aus der Entität gelöscht werden und "myEntity" als Ihre Entität ersetzen soll, die Sie in Ihren Kerndaten definiert haben

  func deleteData() {

  let appDel:AppDelegate = (UIApplication.shared.delegate as! AppDelegate)
  let context:NSManagedObjectContext = appDel.persistentContainer.viewContext
  let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "myEntity")
        fetchRequest.returnsObjectsAsFaults = false

        do
        {
            let results = try context.fetch(fetchRequest)
            for managedObject in results
            {
                let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
                context.delete(managedObjectData)
            }
        } catch let error as NSError {
            print("Deleted all my data in myEntity error : \(error) \(error.userInfo)")
  }
  }
2
Xcodian Solangi

Warum falten Sie nicht die Daten ein, die Sie mit dem vorhandenen Cache erhalten? Ansonsten ist es nicht wirklich "erfrischend", sondern "fängt wieder an" und Sie können die SQLLite-Datei auch löschen oder löschen und neu starten (vorausgesetzt, Sie speichern keine anderen Daten).

2
AlBlue

wenn die Entität viele Einträge enthält, ist der beste Weg, da dies Speicherplatz spart 

 - (void)deleteAll:(NSManagedObjectContext *)managedObjectContext entityName:(NSString *)entityName
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [managedObjectContext setUndoManager:nil];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    [fetchRequest setIncludesPropertyValues:NO];
    [fetchRequest setFetchLimit:100]; // you can change this number if you want
    NSError *error;
    NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    while ([items count] > 0) {
        @autoreleasepool {
            for (NSManagedObject *item in items) {
                [managedObjectContext deleteObject:item];
            }
            if (![managedObjectContext save:&error]) {
                NSLog(@"Error deleting %@ - error:%@",self.entityName, error);
            }
        }
        items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    }
}
1
poyo fever.

Swift 4, iOS 10+
Statische Funktion, die für jede Entität gelten kann, um alle ihre Daten zu entfernen

protocol NSManagedObjectHelper {
}
extension NSManagedObject: NSManagedObjectHelper {
}
extension NSManagedObjectHelper where Self: NSManagedObject {
    static func removeAllObjectsInContext(_ managedContext: NSManagedObjectContext) {
        let request: NSFetchRequest = Self.fetchRequest()
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
        do {
            deleteRequest.resultType = .resultTypeObjectIDs//to clear objects from memory
            let result = try managedContext.execute(deleteRequest) as? NSBatchDeleteResult
            if let objectIDArray = result?.result as? [NSManagedObjectID] {
                let changes = [NSDeletedObjectsKey : objectIDArray]
                /*By calling mergeChangesFromRemoteContextSave, all of the NSManagedObjectContext instances that are referenced will be notified that the list of entities referenced with the NSManagedObjectID array have been deleted and that the objects in memory are stale. This causes the referenced NSManagedObjectContext instances to remove any objects in memory that are loaded which match the NSManagedObjectID instances in the array.*/
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedContext])
            }
            try managedContext.save()
        } catch let error {
            print(error)
        }
    }
}

'Zimmer' ist eine Entität

Room.removeAllObjectsInContext(self.persistentContainer.viewContext)
1
jpulikkottil

In Swift 3.0

 func deleteAllRecords() {
        //delete all data
        let context = appDelegate.persistentContainer.viewContext

        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "YourClassName")
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)

        do {
            try context.execute(deleteRequest)
            try context.save()
        } catch {
            print ("There was an error")
        }
    }
1
Rob-4608

Dieser Code funktioniert sowohl für iOS 9 als auch darunter

class func deleteAllRecords(in entity : String) // entity = Your_Entity_Name
    {

        let context = CoreDataStack.getContext() // Note:- Replace your context here with CoreDataStack.getContext()
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        if #available(iOS 9, *)
        {
            let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
            do
            {
                try context.execute(deleteRequest)
                try context.save()
            }
            catch
            {
                print("There was an error:\(error)")
            }
        }
        else
        {
            do{
                let deleteRequest = try context.fetch(deleteFetch)
                for anItem in deleteRequest {
                    context.delete(anItem as! NSManagedObject)
                }
            }
            catch
            {
                print("There was an error:\(error)")
            }
        }
        CoreDataStack.saveContext() // Note:- Replace your savecontext here with CoreDataStack.saveContext()
    }
1
Varun Naharia
    func deleteAll(entityName: String) {

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
    let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    deleteRequest.resultType = .resultTypeObjectIDs
    guard let context = self.container?.viewContext
        else { print("error in deleteAll")
            return }

    do {
        let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
        let objectIDArray = result?.result as? [NSManagedObjectID]
        let changes: [AnyHashable : Any] = [NSDeletedObjectsKey : objectIDArray as Any]
        NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
    } catch {
        print(error.localizedDescription)
    }
}
0
Matt Bearson

schnelles Löschen von allen Objekten in DB:

func purgeAllData() {
    let uniqueNames = persistentContainer.managedObjectModel.entities.compactMap({ $0.name })

    uniqueNames.forEach { (name) in
      let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)
       let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
         do {
        try persistentContainer.viewContext.execute(batchDeleteRequest)
      } catch {
        let nserror = error as NSError
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
      }
   }
 }
0
gbk

Swift-3-Lösung mit iOS 9 'NSBatchDeleteRequest' und Rückgriff auf frühere iOS-Versionen, die als Erweiterung für 'NSManagedObjectContext' implementiert sind. Apple-Referenz https://developer.Apple.com/library/content/featuredarticles/CoreData_Batch_Guide/BatchDeletes/BatchDeletes.html

extension NSManagedObjectContext {
    func batchDeleteEntities<T: NSManagedObject>(ofType type: T.Type) throws {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type.self))
        if #available(iOS 9.0, *) {
            let request = NSBatchDeleteRequest(fetchRequest: fetchRequest)
            let result = try execute(request) as? NSBatchDeleteResult
            if let objectIDArray = result?.result as? [NSManagedObjectID] {
                let changes = [NSDeletedObjectsKey: objectIDArray]
                NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
            }
        } else {
            fetchRequest.includesPropertyValues = false
            let results = try fetch(fetchRequest)
            if let actualResults = results as? [NSManagedObject], !actualResults.isEmpty {
                actualResults.forEach { delete($0) }
            }
        }
    }
}
0
chriswillow

Verwenden Sie NSBatchDeleteRequest, um mehrere Datensätze zu löschen. Wenn iOS mindestens 9.0 ist. Wenn ein Hintergrund-Thread ausgeführt wird, führen Sie NSManagedObjectContext save aus. Andernfalls verwenden Sie NSFetchRequest, um Datensätze abzurufen und alle Datensätze in der for-Schleife zu löschen.

0
Jeetendra Kumar

in iOS 11.3 und Swift 4.1

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
        let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest )
        batchDeleteRequest.resultType = .resultTypeCount
        do {
            let batchDeleteResult = try dataController.viewContext.execute(batchDeleteRequest) as! NSBatchDeleteResult
            print("The batch delete request has deleted \(batchDeleteResult.result!) records.")
            dataController.viewContext.reset() // reset managed object context (need it for working)
        } catch {
            let updateError = error as NSError
            print("\(updateError), \(updateError.userInfo)")
        }

sie müssen reset nach der Ausführung aufrufen. Wenn nicht, wird die Tabelle nicht aktualisiert.

0
tien113

iOS 9.0 und höher:

NSBatchDeleteRequest wird zum Löschen von Datensätzen in Kerndaten verwendet. Es funktioniert sehr schnell und benötigt weniger Zeit, um alle Datensätze aus einer Entität zu löschen. Es erfordert NSFetchRequest im Argument. Wenn Sie alle Datensätze aus einer Entität löschen möchten, können Sie sie verwenden, und es funktioniert für mich. 

let manageObject:NSManagedObjectContext = appDelegateObject.managedObjectContext

let fetchRequest = NSFetchRequest(entityName: “EnityName”)

let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

let persistCor:NSPersistentStoreCoordinator = appDelegateObject.persistentObject
 do {
        try persistCor.executeRequest(deleteRequest, withContext: manageObject)
        try manageObject.save()
    } catch {
        print(error?.localizedDescription)
    }
0

Die Antwort von Swift 2.0 von Dave Delongs stürzte bei mir ab (in iOS 9)

Aber das hat funktioniert:

let fetchRequest = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

    do {
        try managedObjectContext.executeRequest(deleteRequest)
        try managedObjectContext.save()
    }
    catch let error as NSError {
       // Handle error
    }
0
g_low