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.
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:
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
}
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).
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
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];
}
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")
}
}
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")
}
}
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)")
}
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.
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"];
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)")
}
}
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)")
}
}
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)")
}
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)")
}
}
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).
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];
}
}
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)
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")
}
}
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()
}
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)
}
}
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)")
}
}
}
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) }
}
}
}
}
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.
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.
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)
}
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
}