Alle Einträge in Core Data löschen / zurücksetzen?


235

Kennen Sie eine Möglichkeit, alle in Core Data gespeicherten Einträge zu löschen? Mein Schema sollte gleich bleiben; Ich möchte es nur auf leer zurücksetzen.


Bearbeiten

Ich möchte dies programmgesteuert tun, damit ein Benutzer im Wesentlichen eine resetTaste drücken kann.


6
Viele der folgenden Antworten sind datiert. Verwenden Sie NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Antworten:


198

Sie können die Datei weiterhin programmgesteuert mit der Methode NSFileManager: removeItemAtPath :: löschen.

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

Fügen Sie dann einfach den persistenten Speicher wieder hinzu, um sicherzustellen, dass er ordnungsgemäß neu erstellt wird.

Die programmatische Methode zum Durchlaufen jeder Entität ist sowohl langsamer als auch fehleranfällig. Auf diese Weise können Sie einige Entitäten löschen und andere nicht. Sie müssen jedoch weiterhin sicherstellen, dass Sie die referenzielle Integrität beibehalten, da Sie Ihre Änderungen sonst nicht beibehalten können.

Das Entfernen und Neuerstellen des Speichers ist schnell und sicher und kann zur Laufzeit programmgesteuert durchgeführt werden.

Update für iOS5 +

Mit der Einführung eines externen Binärspeichers (ermöglicht ExternalBinaryDataStorage oder Store in External Record File) in iOS 5 und OS X 10.7 reicht es nicht aus, nur Dateien zu löschen, auf die storeURLs verweisen. Sie lassen die externen Datensatzdateien zurück. Da das Namensschema dieser externen Datensatzdateien nicht öffentlich ist, habe ich noch keine universelle Lösung. - an0 8. Mai 12 um 23:00 Uhr


1
Dies ist wahrscheinlich die beste Lösung für Zuverlässigkeit. Wenn ich einige, aber nicht alle Daten löschen wollte, würde ich dies verwenden: stackoverflow.com/questions/1077810/…
Michael Grinich

12
Ich weiß, wie man den storeCoordinator richtig abruft. Ich weiß jedoch nicht, wie ich den persistentStore bekommen soll. Könnten Sie bitte ein richtiges Beispiel geben, anstatt nur: NSPersistentStore * store = ...;
Pascal Klein

11
[[NSFileManager defaultManager] removeItemAtURL: storeURL error: & error] ist besser.
an0

3
@Pascal Wenn Sie den Geschäftskoordinator erhalten können, haben Sie über die Eigenschaft persistentStores Zugriff auf alle persistenten Speicher.
Mihai Damian

2
Beispielcode einschließlich der Wiederherstellung eines neuen leeren Speichers hier: stackoverflow.com/a/8467628
Joshua C. Lerner

140

Sie können die SQLite-Datei löschen - aber ich entscheide mich dafür, indem ich die Tabellen einzeln mit folgenden Funktionen lösche:

- (void) deleteAllObjects: (NSString *) entityDescription  {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];


    for (NSManagedObject *managedObject in items) {
        [_managedObjectContext deleteObject:managedObject];
        DLog(@"%@ object deleted",entityDescription);
    }
    if (![_managedObjectContext save:&error]) {
        DLog(@"Error deleting %@ - error:%@",entityDescription,error);
    }

}

Der Grund, warum ich mich für Tabelle für Tabelle entschieden habe, ist, dass ich bei der Programmierung bestätige, dass das Löschen des Inhalts der Tabelle sinnvoll ist und es keine Daten gibt, die ich lieber behalten möchte.

Dies zu tun ist viel langsamer als nur das Löschen der Datei und ich werde zu einem Löschen von Dateien wechseln, wenn diese Methode zu lange dauert.


Tolle Lösung. Vielen Dank. Was ist DLog ()?
Michael Grinich

Ah ja - sorry, das ist eine spezielle Funktion, die ich benutze und die nur dann einen NSLog ausführt, wenn der Build ein DEBUG-Build ist - einfach durch NSLog ersetzen.
Grouchal

6
Sie können eine Implementierung von DLog hier sehen: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long

3
Das funktioniert gut für mich. Gibt es eine Möglichkeit, alle Objekte einer bestimmten Entität mit einem Befehl zu löschen, um die Geschwindigkeit zu erhöhen? Wie in SQL können Sie auch DROP TABLE entity_name ausführen. Ich möchte nicht die gesamte SQL-Datei löschen, da ich nur alle Objekte einer bestimmten Entität löschen möchte, nicht andere Entitäten.
ma11hew28

8
Verwenden Sie NSDictionary * allEntities = _managedObjectModel.entitiesByName; Um alle Entitäten in Ihrem Modell abzurufen, können Sie die Schlüssel in diesem NSDictionary durchlaufen, um alle Entitäten im Geschäft zu löschen.
adam0101

60

Aktualisierte Lösung für iOS 10+

Verwenden Sie NSBatchDeleteRequestdiese Option, um alle Objekte in der Entität zu löschen, ohne sie in den Speicher laden oder durchlaufen zu müssen.

// create the delete request for the specified entity
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = MyEntity.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

// get reference to the persistent container
let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

// perform the delete
do {
    try persistentContainer.viewContext.execute(deleteRequest)
} catch let error as NSError {
    print(error)
}

Dieser Code wurde für iOS 10 und Swift 3 aktualisiert. Wenn Sie iOS 9 unterstützen müssen, lesen Sie diese Frage .

Quellen:


3
Ich würde diesen ganzen Block innerhalb eines Ort moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect

2
Stellen Sie sicher, dass Sie sehen, warum Einträge nicht gelöscht werden, bis die App neu gestartet wird oder ich meine NSBatchDeleteRequest zweimal ausführe. Lange Geschichte, der obige Code ist NICHT genug, wenn die Entitäten in den Speicher geladen werden
Honey

38

Ich habe eine clearStoresMethode geschrieben, die jeden Speicher durchläuft und sowohl vom Koordinator als auch vom Dateisystem löscht (Fehlerbehandlung beiseite gelassen):

NSArray *stores = [persistentStoreCoordinator persistentStores];

for(NSPersistentStore *store in stores) {
    [persistentStoreCoordinator removePersistentStore:store error:nil];
    [[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}

[persistentStoreCoordinator release], persistentStoreCoordinator = nil;

Diese Methode befindet sich in einer coreDataHelperKlasse, die sich unter anderem darum kümmert, den persistentStore zu erstellen, wenn er gleich Null ist.


"Keine bekannte Klassenmethode für den Selektor 'persistentStores'"
Aviram Netanel

27

Ich entferne alle Daten aus den Kerndaten einer Schaltfläche Ereignis in einer HomeViewController-Klasse: Dieser Artikel hat mir so sehr geholfen, dass ich dachte, ich würde einen Beitrag leisten.

-(IBAction)buttonReset:(id)sender
{
    NSLog(@"buttonReset Pressed");

    //Erase the persistent store from coordinator and also file manager.
    NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
    NSError *error = nil;
    NSURL *storeURL = store.URL;
    [self.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    NSLog(@"Data Reset");

    //Make new persistent store for future saves   (Taken From Above Answer)
    if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // do something with the error
    }

}

Beachten Sie, dass ich zum Aufrufen von self.persistentStoreCoordinator eine Eigenschaft im Home View Controller deklariert habe. (Machen Sie sich keine Sorgen über den verwalteten Objekttext, den ich zum Speichern und Laden verwende.)

@property (nonatomic, retain) NSManagedObjectContext        *   managedObjectContext;
@property (nonatomic, retain) NSPersistentStoreCoordinator  *   persistentStoreCoordinator;

Dann in der AppDelegate ApplicationDidFinishLaunching rechts unten einen HomeViewController erstellen, den ich habe:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;

@ayteat, hat das für dich funktioniert?. für mich funktioniert es nicht, bitte werfen Sie einen Blick auf diese stackoverflow.com/questions/14646595/…
Ranjit

1
Dies ist die Antwort, außer "AppDelegate * ad = [[UIApplication sharedApplication] delegate];" und ersetzen Sie sich durch Anzeige. und kopieren Sie nicht die letzten zwei Codebits
Cescy

1
Warum rufen Sie nicht reset für manageObjectContext auf? Was ist, wenn Sie einen starken Bezug zu ManagedObject haben?
Parag Bafna

@ParagBafna Sie haben Recht. Im obigen Codebeispiel wird davon ausgegangen, dass keine starken Verweise auf verwaltete Objekte vorhanden sind. Wenn Sie welche haben, sollten Sie sich den Aufruf von 'reset' im verwalteten Objekttext ansehen und alle verwalteten Objekte, die Sie haben, de-referenzieren.
Atreat

Hey danke. Gibt es auch eine Möglichkeit, dies beim App-Upgrade zu tun? Um genau zu sein, ist meine Anforderung, wenn ich unsere nächste Version der App rolle. Wenn der Benutzer seine App über den AppStore aktualisiert, sollten die Kerndaten und SQLite-Dateien gelöscht und neu initialisiert werden, um leer zu sein. Ich habe herausgefunden, wie ich das erste Startereignis einer App mithilfe eines Bool-Werts in NSUserDefaults erkennen und diesen Wert in didfinishLaunchingWithOptions des App-Delegaten überprüfen kann, habe aber nicht verstanden, wie all diese Dinge gelöscht werden können. Da es keine Schaltfläche gibt und der App-Delegat meinen "persistentStore" nicht erkennt, um ihn wie oben beschrieben zu löschen. irgendeine Hilfe?
Tejas

19

MagicalRecord macht dies sehr einfach.

[MyCoreDataObject MR_truncateAll];

16
Das ist cool, aber nicht zum Thema, da ich eine CoreData-Lösung angegeben habe
Michael Grinich

8
Active Record Fetching ist eine zentrale Datenlösung.
Casademora

7
Eine solche Antwort geht jedoch über den Rahmen der Frage hinaus. Es gibt keinen Grund anzunehmen, dass er dazu ein zusätzliches Framework verwenden möchte.
Jpswain

Ich würde argumentieren, dass dies die Frage nicht beantwortet. Dies ist eine gute Möglichkeit, Einträge aus einer Entität zu entfernen, nicht aus allen Entitäten ...! Wie werden alle Entitäten im Modell aufgelistet und gesendet?MR_truncateAll ?
Fatuhoku

Zeigen Sie die Quelle für MR_truncateAll an. Sie ruft alle Objekte ab, jedoch nicht deren Eigenschaften (da wir die NSMOs verwerfen möchten). Anschließend werden die Objekte für die angegebene Entität durchlaufen und gelöscht. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t

19

iOS9 +, Swift 2

Löschen Sie alle Objekte in allen Entitäten

func clearCoreDataStore() {
    let entities = managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.executeRequest(deleteReqest)
        } catch {
            print(error)
        }
    }
}

1
Stellen Sie sicher, dass Sie sehen, warum Einträge nicht gelöscht werden, bis die App neu gestartet wird oder ich meine NSBatchDeleteRequest zweimal ausführe. Lange Geschichte, der obige Code ist NICHT genug, wenn die Entitäten in den Speicher geladen werden
Honey

13

[Späte Antwort als Antwort auf ein Kopfgeld, das nach neueren Antworten fragt]

Blick auf frühere Antworten,

  • Das Abrufen und Löschen aller Elemente, wie von @Grouchal und anderen vorgeschlagen, ist immer noch eine effektive und nützliche Lösung. Wenn Sie sehr große Datenspeicher haben, ist dies möglicherweise langsam, funktioniert aber dennoch sehr gut.
  • Das einfache Entfernen des Datenspeichers ist, wie Sie und @groundhog bemerken, nicht mehr wirksam. Es ist veraltet, auch wenn Sie keinen externen Binärspeicher verwenden, da iOS 7 den WAL-Modus für SQLite-Journale verwendet. Im WAL-Modus befinden sich möglicherweise (möglicherweise große) Journaldateien für jeden persistenten Core Data-Speicher.

Es gibt jedoch einen anderen, ähnlichen Ansatz zum Entfernen des dauerhaften Speichers, der funktioniert. Der Schlüssel besteht darin, Ihre persistente Speicherdatei in einem eigenen Unterverzeichnis abzulegen, das nichts anderes enthält. Stecken Sie es nicht einfach in das Dokumentenverzeichnis (oder wo auch immer), sondern erstellen Sie ein neues Unterverzeichnis nur für den persistenten Speicher. Der Inhalt dieses Verzeichnisses ist letztendlich die persistente Speicherdatei, die Journaldateien und die externen Binärdateien. Wenn Sie den gesamten Datenspeicher zerstören möchten, löschen Sie dieses Verzeichnis, und alle verschwinden.

Sie würden so etwas tun, wenn Sie Ihren dauerhaften Speicher einrichten:

NSURL *storeDirectoryURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"persistent-store"];
if ([[NSFileManager defaultManager] createDirectoryAtURL:storeDirectoryURL
        withIntermediateDirectories:NO
        attributes:nil
        error:nil]) {
    NSURL *storeURL = [storeDirectoryURL URLByAppendingPathComponent:@"MyApp.sqlite"];
    // continue with storeURL as usual...
}

Wenn Sie dann den Laden entfernen wollten,

[[NSFileManager defaultManager] removeItemAtURL:storeDirectoryURL error:nil];

Dadurch werden sowohl das benutzerdefinierte Unterverzeichnis als auch alle darin enthaltenen Core Data-Dateien rekursiv entfernt.

Dies funktioniert nur, wenn sich Ihr persistenter Speicher nicht bereits im selben Ordner wie andere wichtige Daten befindet . Wie das Dokumentenverzeichnis, das wahrscheinlich andere nützliche Dinge enthält. Wenn das Ihre Situation, könnte man den gleichen Effekt durch die Suche nach Dateien, die Sie tun behalten wollen und alles andere zu entfernen. Etwas wie:

NSString *docsDirectoryPath = [[self applicationDocumentsDirectory] path];
NSArray *docsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsDirectoryPath error:nil];
for (NSString *docsDirectoryItem in docsDirectoryContents) {
    // Look at docsDirectoryItem. If it's something you want to keep, do nothing.
    // If it's something you don't recognize, remove it.
}

Dieser Ansatz kann fehleranfällig sein . Sie müssen absolut sicher sein, dass Sie jede Datei kennen, die Sie behalten möchten, da Sie sonst möglicherweise wichtige Daten entfernen. Auf der anderen Seite können Sie die externen Binärdateien entfernen, ohne den Datei- / Verzeichnisnamen zu kennen, in dem sie gespeichert wurden.


Wenn Sie Angst vor der Wal-Datei haben, deaktivieren Sie sie einfach
onmyway133

11

Hier ist eine kombinierte Lösung zum Löschen von Kerndaten.

- (void)deleteAllObjectsInCoreData
{
    NSArray *allEntities = self.managedObjectModel.entities;
    for (NSEntityDescription *entityDescription in allEntities)
    {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];

        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;

        NSError *error;
        NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (error) {
                NSLog(@"Error requesting items from Core Data: %@", [error localizedDescription]);
            }

        for (NSManagedObject *managedObject in items) {
            [self.managedObjectContext deleteObject:managedObject];
        }

        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }  
}

10

Wenn Sie alle Objekte löschen und die Sicherungsdateien nicht löschen möchten, können Sie folgende Methoden verwenden:

- (void)deleteAllObjectsInContext:(NSManagedObjectContext *)context
                       usingModel:(NSManagedObjectModel *)model
{
    NSArray *entities = model.entities;
    for (NSEntityDescription *entityDescription in entities) {
        [self deleteAllObjectsWithEntityName:entityDescription.name
                                   inContext:context];
    }
}

- (void)deleteAllObjectsWithEntityName:(NSString *)entityName
                             inContext:(NSManagedObjectContext *)context
{
    NSFetchRequest *fetchRequest =
        [NSFetchRequest fetchRequestWithEntityName:entityName];
    fetchRequest.includesPropertyValues = NO;
    fetchRequest.includesSubentities = NO;

    NSError *error;
    NSArray *items = [context executeFetchRequest:fetchRequest error:&error];

    for (NSManagedObject *managedObject in items) {
        [context deleteObject:managedObject];
        NSLog(@"Deleted %@", entityName);
    }
}

Beachten Sie, dass es sehr langsam sein kann (hängt davon ab, wie viele Objekte sich in Ihrem Objektdiagramm befinden).


wie man die älteren Daten entfernt (sagen wir drei Tabellen, von einer Tabelle möchte ich Daten löschen), wenn App-Updates
Madan Mohan

6

Wenn Sie die Route zum Löschen aller Objekte ausführen möchten (was viel einfacher ist als das Herunterfahren des Kerndatenstapels, aber weniger leistungsfähig), ist dies eine bessere Implementierung:

- (void)deleteAllManagedObjectsInModel:(NSManagedObjectModel *)managedObjectModel context:(NSManagedObjectContext *)managedObjectContext
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [managedObjectContext performBlockAndWait:^{
            for (NSEntityDescription *entity in managedObjectModel) {
                NSFetchRequest *fetchRequest = [NSFetchRequest new];
                [fetchRequest setEntity:entity];
                [fetchRequest setIncludesSubentities:NO];
                NSArray *objects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
                for (NSManagedObject *managedObject in objects) {
                    [managedObjectContext deleteObject:managedObject];
                }            
            }

            [managedObjectContext save:nil];
        }];
    }];
    [operation setCompletionBlock:^{
        // Do stuff once the truncation is complete
    }];
    [operation start];
}

Diese Implementierung nutzt NSOperationdas Löschen des Hauptthreads und die Benachrichtigung nach Abschluss. Möglicherweise möchten Sie eine Benachrichtigung oder etwas innerhalb des Abschlussblocks ausgeben, um den Status zurück zum Haupt-Thread zu leiten.


Beachten Sie, dass Ihr NSManagedObjectContext wie folgt initialisiert werden NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];muss, um diese Methode zu verwenden. Andernfalls wird der folgende Fehler angezeigt :Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Wird

6

iOS 10 + Swift 3-Lösung:

func clearCoreDataStore() {
    let delegate = UIApplication.shared.delegate as! AppDelegate
    let context = delegate.persistentContainer.viewContext

    for i in 0...delegate.persistentContainer.managedObjectModel.entities.count-1 {
        let entity = delegate.persistentContainer.managedObjectModel.entities[i]

        do {
            let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
            let deleterequest = NSBatchDeleteRequest(fetchRequest: query)
            try context.execute(deleterequest)
            try context.save()

        } catch let error as NSError {
            print("Error: \(error.localizedDescription)")
            abort()
        }
    }
}

Durchläuft alle Kerndatenentitäten und löscht sie


4

Danke für den Beitrag. Ich folgte ihm und es funktionierte für mich. Aber ich hatte ein anderes Problem, das in keiner der Antworten erwähnt wurde. Ich bin mir also nicht sicher, ob es nur ich war.

Wie auch immer, ich dachte, ich würde hier das Problem und meinen Weg, der es gelöst hat, posten.

Ich hatte ein paar Datensätze in der Datenbank, ich wollte alles bereinigen, bevor ich neue Daten in die Datenbank schreibe, also habe ich alles getan, einschließlich

[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 

und dann verwendet, managedObjectContextum auf die Datenbank zuzugreifen (soll jetzt leer sein), irgendwie waren die Daten noch da. Nach einer gewissen Zeit der Fehlersuche, fand ich , dass ich zurücksetzen müssen managedObjectContext, managedObject, managedObjectModelund persistentStoreCoordinator, bevor ich managedObjectContextdie dabase zuzugreifen. Jetzt habe ich eine saubere Datenbank zum Schreiben.


Durch das Zurücksetzen von verwalteterObjectContext, verwalteterObject, verwalteterObjectModel und persistenterStoreCoordinator wird die Datei mit der Datenbank nach dem Löschen zurückgesetzt.
Daniel Brower

4

Hier ist eine etwas vereinfachte Version mit weniger Aufrufen von AppDelegate self und dem letzten Code, der in der am besten bewerteten Antwort nicht berücksichtigt wurde. Außerdem wurde die Fehlermeldung "Der persistente Speicher des Objekts ist über den Koordinator dieses NSManagedObjectContext nicht erreichbar" angezeigt, sodass ich ihn nur wieder hinzufügen musste.

NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
NSPersistentStore *store = [[storeCoordinator persistentStores] lastObject];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"dataModel"];
NSError *error;

[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

if (storeCoordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}

4

schnelle Lösung:

class func deleteAllManagedObjects() {

        let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "mom")
        let mom = NSManagedObjectModel(contentsOfURL: modelURL)

        for entityName in mom.entitiesByName.keys {
            let fr = NSFetchRequest(entityName: entityName as String)
            let a = Utility.managedObjectContext().executeFetchRequest(fr, error: nil) as [NSManagedObject]
            for mo in a {
                Utility.managedObjectContext().deleteObject(mo)
            }
        }

        Utility.managedObjectContext().save(nil)
    }

Für schnelle 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido

3

Als Kurzreferenz zum Speichern der Suche an anderer Stelle können Sie den dauerhaften Speicher nach dem Löschen neu erstellen:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}

Ich habe Ihren Code ausprobiert, aber xcode löst eine Ausnahme in dieser Zeile aus. Also, was Sie dazu zu sagen haben.
Ranjit

3

Mehrere gute Antworten auf diese Frage. Hier ist eine schöne, prägnante. Die ersten beiden Zeilen löschen die SQLite-Datenbank. Anschließend löscht die for: -Schleife alle Objekte im ManagedObjectContext-Speicher.

NSURL *storeURL = [[(FXYAppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppName.sqlite"];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
for (NSManagedObject *ct in [self.managedObjectContext registeredObjects]) {
    [self.managedObjectContext deleteObject:ct];
}

1
Missbrauche die Delegation nicht zu diesem Zweck: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner

1
Ich stimme @MichaelDorner zu. Das Hinzufügen von zu viel zu AppDelegate kann die Leistung beeinträchtigen und die Größe Ihrer Binärdatei durch ein miteinander verbundenes Spinnennetz von Abhängigkeiten aufblähen, bei denen AppDelegate plötzlich in jede Klasse aufgenommen werden muss. Wenn dies auftritt, erstellen Sie einen separaten Controller für diesen Zweck. AppDelegate sollte für die grundlegende Initialisierung und Behandlung von Statusänderungen in der Anwendung erhalten bleiben, nicht viel mehr.
JCPennypincher

2

Sie können auch alle Entitätsnamen finden und nach Namen löschen. Es ist eine längere Version, funktioniert aber gut, so dass Sie nicht mit dem Persistenzspeicher arbeiten müssen

 - (void)clearCoreData
{
NSError *error;
NSEntityDescription *des = [NSEntityDescription entityForName:@"Any_Entity_Name" inManagedObjectContext:_managedObjectContext];
NSManagedObjectModel *model = [des managedObjectModel];
NSArray *entityNames = [[model entities] valueForKey:@"name"];

for (NSString *entityName in entityNames){

    NSFetchRequest *deleteAll = [NSFetchRequest fetchRequestWithEntityName:entityName];
    NSArray *matches = [self.database.managedObjectContext executeFetchRequest:deleteAll error:&error];

}
    if (matches.count > 0){
        for (id obj in matches){

            [_managedObjectContext deleteObject:obj];
        }
       [self.database.managedObjectContext save:&error];
    }
}

Geben Sie für "Any_Entity_Name" nur einen Namen Ihrer Entität an. Wir müssen nur die Entitätsbeschreibung herausfinden, in der sich Ihre Entitäten befinden. ValueForKey @ "name" gibt alle Entitätsnamen zurück. Vergessen Sie nicht zu speichern.


2

Die akzeptierte Antwort ist korrekt, wenn das Entfernen der URL durch NSFileManager korrekt ist. Wie in der Bearbeitung von iOS 5+ angegeben, wird der persistente Speicher jedoch nicht nur durch eine Datei dargestellt. Für den SQLite-Speicher sind es * .sqlite, * .sqlite-shm und * .sqlite-wal ... zum Glück können wir seit iOS 7+ die Methode verwenden

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: options: error:]

Um sich um das Entfernen zu kümmern, sollte der Code ungefähr so ​​aussehen:

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSString *storeName = ...;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL.path options:@{NSPersistentStoreUbiquitousContentNameKey: storeName} error:&error];

2
Sie müssen das Optionsdiktat übergeben, insbesondere den Geschäftsnamen, z. B.: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
Tomi44g

2

Swift 4/5, iOS 9+

Durch die Neuerstellung der gesamten CoreDataSQLite-Datei wird sichergestellt, dass alle Daten gelöscht werden. Daher werden alle Entitäten gelöscht. Rufen Sie einfach an deleteAndRebuild().

class CoreDataStack {
    // Change this
    static let datamodelName = "ProjectName"
    static let storeType = "sqlite"

    static let persistentContainer = NSPersistentContainer(name: datamodelName)
    private static let url: URL = {
        let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")

        assert(FileManager.default.fileExists(atPath: url.path))

        return url
    }()

    static func loadStores() {
        persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
            if let error = error {
                fatalError(error.localizedDescription)
            }
        })
    }

    static func deleteAndRebuild() {
        try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)

        loadStores()
    }
}

Beachten Sie für jeden, der dies verwendet, dass es nur beim "ersten Mal" abstürzt, wenn dort keine SQL-Datei vorhanden ist (ich habe in meiner Antwort nur einen "Wächter" verwendet)
Fattie

1

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

func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
    var context = NSManagedObjectContext()
    if #available(iOS 10.0, *) {
        context = self.persistentContainer.viewContext
    } else {
        context = self.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)")
    }
}

1

Hier ist eine Version, die jeden Datensatz in jeder Tabelle löscht, die Sie haben.

Swift 4

static func resetDatabase() {
    do {
        try dataStore.persistentStoreCoordinator.managedObjectModel.entities.forEach { (entity) in
            if let name = entity.name {
                let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                let request = NSBatchDeleteRequest(fetchRequest: fetch)
                try mainContext.execute(request)
            }
        }

        try mainContext.save()
    } catch {
        print("error resenting the database: \(error.localizedDescription)")
    }
}

1

Eine andere Methode (abgesehen von einer Batch-Anforderung zum Löschen), die ich häufig verwende (basierend auf den App-Anforderungen), ist das Zurücksetzen des persistenten Speichers. Die Implementierung sieht für iOS 10+ und Swift folgendermaßen aus (vorausgesetzt, Sie haben eine CoreDataManager-Klasse):

let persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "<Data-Model-Name>“)
    container.loadPersistentStores(completionHandler: { (storeDescription, err) in
        if let err = err {
            fatalError("loading of store failed: \(err)")
        }
    })
    return container
}()

func resetPersistentStore() {

    if let persistentStore = persistentContainer.persistentStoreCoordinator.persistentStores.last {
        let storeURL = persistentContainer.persistentStoreCoordinator.url(for: persistentStore)

        do {
            try persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: NSSQLiteStoreType, options: nil)
        } catch {
            print("failed to destroy persistent store:", error.localizedDescription)
        }

        do {
            try persistentContainer.persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
        } catch {
            print("failed to re-add persistent store:", error.localizedDescription)
        }
    }

}

Ein Vorteil dieser Methode besteht darin, dass sie einfacher ist, insbesondere wenn Sie eine Vielzahl von Datensätzen für zahlreiche Entitäten in Ihren Kerndaten haben. In diesem Fall wäre eine Anforderung zum Löschen eines Stapels speicherintensiv.


1

Swift 5.1 Lösung

public static func reset() {
    let coordinator = _persistentContainer.persistentStoreCoordinator
    for store in coordinator.persistentStores where store.url != nil {
        try? coordinator.remove(store)
        try? FileManager.default.removeItem(atPath: store.url!.path)
    }
}

0

Die persistente Speicherdatei löschen und einen neuen persistenten Speicherkoordinator einrichten?


6
Durch eine Bereinigung werden die persistenten Speicherdateien zum Glück nicht entfernt. Das wäre ein Rezept für eine Katastrophe, wenn es wahr wäre.
Hunter

0

Löschen Sie SQLite aus Ihrer DateiURLPath und erstellen Sie es.


Ich meinte, wenn die App installiert ist.
Michael Grinich

0

Angenommen, Sie verwenden MagicalRecordund haben einen Standard-Persistenzspeicher:

Ich mag nicht alle Lösungen, die davon ausgehen, dass bestimmte Dateien vorhanden sind und / oder die Eingabe der Entitätsnamen oder -klassen erfordern. Dies ist eine schnelle und sichere Methode zum schnellen Löschen aller Daten aus allen Entitäten. Nach dem Löschen wird auch ein neuer Stapel neu erstellt (ich bin mir eigentlich nicht sicher, wie wichtig dieser Teil ist).

Es ist ideal für Situationen im "Logout" -Stil, in denen Sie alles löschen möchten, aber einen funktionierenden Speicher und einen Moc haben, um neue Daten zu erhalten (sobald sich der Benutzer anmeldet ...).

extension NSManagedObject {

    class func dropAllData() {

        MagicalRecord.saveWithBlock({ context in

            for name in NSManagedObjectModel.MR_defaultManagedObjectModel().entitiesByName.keys {
                do { try self.deleteAll(name, context: context) }
                catch { print("⚠️ ✏️ Error when deleting \(name): \(error)") }
            }

            }) { done, err in
                MagicalRecord.cleanUp()
                MagicalRecord.setupCoreDataStackWithStoreNamed("myStoreName")
        }
    }

    private class func deleteAll(name: String, context ctx: NSManagedObjectContext) throws {
        let all = NSFetchRequest(entityName: name)
        all.includesPropertyValues = false

        let allObjs = try ctx.executeFetchRequest(all)
        for obj in allObjs {
            obj.MR_deleteEntityInContext(ctx)
        }

    }
}

0

Benutze das

+(NSArray *)fetchDataFromEntity:(NSString *)entityName context:(NSManagedObjectContext *)context
{
    NSFetchRequest * fetchRequest =[[NSFetchRequest alloc] init];
    NSEntityDescription * CategoriesEntity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
    [fetchRequest setEntity:CategoriesEntity];

    NSError * error;
    NSInteger count = [context countForFetchRequest:fetchRequest error:&error];

    if (count && count>0) {

        NSArray * fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects && fetchedObjects.count>0) {

            return fetchedObjects;
        }else
            return nil;

    }
    else
        return nil;
}
+ (void)deleteObjectsOfArray:(NSMutableArray*)ary context:(NSManagedObjectContext *)context {
    for (NSManagedObject * obj in ary) {
        [context deleteObject:obj];
    }
    NSError *saveError = nil;
    [context save:&saveError];
}
+ (void)deleteEntity:(NSString *)entityName context:(NSManagedObjectContext *)context {
    NSArray *listArray = [self fetchDataFromEntity:entityName context:context];
    [self deleteObjectsOfArray:[NSMutableArray arrayWithArray:listArray] context:context];
}

0

Ich habe Grouchals Code genommen und um ihn zu beschleunigen, habe ich die Aufzählung mit dem gleichzeitigen Modus ( NSEnumerationConcurrent) verwendet. Sie wurde im Vergleich zur for-Schleife etwas schneller (in meiner App habe ich diese Funktion für Tester hinzugefügt, damit sie Daten löschen und Testfälle ausführen können, anstatt und zu löschen App installieren)

- (void)resetObjects
{
    [self deleteAllObjectsInEntity:@"Entity1"];
    [self deleteAllObjectsInEntity:@"Entity2"];
    [self deleteAllObjectsInEntity:@"Entity3"];
    [self deleteAllObjectsInEntity:@"Entity4"];
}

-(void) deleteAllObjectsInEntity:(NSString*) entityName
{
    MainDataContext *coreDataContext = [MainDataContext sharedInstance];
    NSManagedObjectContext *currentContext = coreDataContext.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:currentContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [currentContext executeFetchRequest:fetchRequest error:&error];

    [items enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSManagedObject * obj, NSUInteger idx, BOOL *stop) {
        [currentContext deleteObject:obj];
    }];


    if (![currentContext save:&error]) {
        NSLog(@"Error deleting %@ - error:%@",entityName,error);
    }
}

0

hier meine swift3 version zum löschen aller aufzeichnungen. 'Benutzer' ist der Entitätsname

@IBAction func btnDelAll_touchupinside(_ sender: Any) {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedObjectContext = appDelegate.persistentContainer.viewContext

    let fetchReq = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
    let req = NSBatchDeleteRequest(fetchRequest: fetchReq)

    do {
        try managedObjectContext.execute(req)

    } catch {
        // Error Handling
    }   
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.