Supprimer / réinitialiser toutes les entrées dans Core Data?

235

Connaissez-vous un moyen de supprimer toutes les entrées stockées dans Core Data? Mon schéma doit rester le même; Je veux juste le remettre à zéro.


Éditer

Je cherche à le faire par programme afin qu'un utilisateur puisse essentiellement resetappuyer sur un bouton.

Michael Grinich
la source
6
Beaucoup des réponses ci-dessous sont datées. Utilisez NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch
Copie possible des données
TheNeil

Réponses:

198

Vous pouvez toujours supprimer le fichier par programme, à l'aide de la méthode NSFileManager: removeItemAtPath ::.

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

Ensuite, ajoutez simplement le magasin persistant pour vous assurer qu'il est recréé correctement.

La manière programmatique d'itérer à travers chaque entité est à la fois plus lente et sujette aux erreurs. L'utilisation de cette façon est si vous souhaitez supprimer certaines entités et pas d'autres. Cependant, vous devez toujours vous assurer de conserver l'intégrité référentielle ou vous ne pourrez pas conserver vos modifications.

Le simple fait de supprimer le magasin et de le recréer est à la fois rapide et sûr, et peut certainement être effectué par programme lors de l'exécution.

Mise à jour pour iOS5 +

Avec l'introduction du stockage binaire externe (permetExternalBinaryDataStorage ou Store in External Record File) dans iOS 5 et OS X 10.7, il ne suffit pas de supprimer les fichiers pointés par storeURLs. Vous laisserez les fichiers d'enregistrement externes derrière. Étant donné que le schéma de dénomination de ces fichiers d'enregistrement externes n'est pas public, je n'ai pas encore de solution universelle. - an0 8 mai 12 à 23h00

marmotte
la source
1
C'est probablement la meilleure solution pour la fiabilité. Si je voulais supprimer certaines données mais pas toutes, j'utiliserais ceci: stackoverflow.com/questions/1077810/…
Michael Grinich
12
Je sais comment récupérer correctement le storeCoordinator. Cependant, je ne sais pas comment obtenir le persistentStore. Pourriez-vous s'il vous plaît donner un exemple approprié au lieu de simplement: NSPersistentStore * store = ...;
Pascal Klein
11
[[NSFileManager defaultManager] removeItemAtURL: erreur storeURL: & error] est préférable.
an0
3
@Pascal Si vous pouvez obtenir le coordinateur de magasin, alors vous avez accès à tous ses magasins persistants via la propriété persistentStores.
Mihai Damian
2
Exemple de code comprenant comment recréer un nouveau magasin vide ici: stackoverflow.com/a/8467628
Joshua C. Lerner
140

Vous pouvez supprimer le fichier SQLite - mais je choisis de le faire en purgeant les tables individuellement avec une fonction:

- (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);
    }

}

La raison pour laquelle j'ai choisi de le faire table par table, c'est que cela me fait confirmer pendant la programmation que la suppression du contenu de la table est raisonnable et qu'il n'y a pas de données que je préfère conserver.

Le faire est beaucoup plus lent que la simple suppression du fichier et je passerai à une suppression de fichier si cette méthode prend trop de temps.

Grouchal
la source
Excellente solution. Merci. Qu'est-ce que DLog ()?
Michael Grinich
Ah oui - désolé c'est une fonction spéciale que j'utilise qui ne fait qu'un NSLog quand la build est une build DEBUG - remplacez simplement par NSLog.
Grouchal
6
Vous pouvez voir une implémentation de DLog ici: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long
3
Cela fonctionne bien pour moi. Mais pour accélérer les choses, existe-t-il un moyen de supprimer tous les objets d'une certaine entité avec une seule commande? Comme en SQL, vous pourriez faire quelque chose comme, DROP TABLE nom_entité. Je ne souhaite pas supprimer l'intégralité du fichier SQL car je souhaite uniquement supprimer tous les objets d'une entité spécifique, pas d'autres entités.
ma11hew28
8
Utilisez NSDictionary * allEntities = _managedObjectModel.entitiesByName; pour obtenir toutes les entités de votre modèle, puis vous pouvez parcourir les clés de ce NSDictionary pour purger toutes les entités du magasin.
adam0101
60

Solution mise à jour pour iOS 10+

Permet NSBatchDeleteRequestde supprimer tous les objets de l'entité sans avoir à les charger en mémoire ou à les parcourir.

// 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)
}

Ce code a été mis à jour pour iOS 10 et Swift 3. Si vous devez prendre en charge iOS 9, consultez cette question .

Sources:

Suragch
la source
3
Je mettrais ce bloc entier à l' intérieur d' un moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect
2
Assurez-vous de voir pourquoi les entrées ne sont pas supprimées jusqu'à ce que l'application soit redémarrée ou que j'exécute ma NSBatchDeleteRequest deux fois? Longue histoire, le code ci-dessus n'est pas suffisant si les entités sont chargées dans la mémoire
Honey
38

J'ai écrit une clearStoresméthode qui passe par chaque magasin et la supprime à la fois du coordinateur et du système de fichiers (gestion des erreurs laissée de côté):

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;

Cette méthode est à l'intérieur d'une coreDataHelperclasse qui s'occupe (entre autres) de créer le persistentStore quand il est nul.

samvermette
la source
"aucune méthode de classe connue pour le sélecteur 'persistentStores'"
Aviram Netanel
27

Je supprime toutes les données des données de base sur un événement de bouton dans une classe HomeViewController: Cet article m'a tellement aidé que je pensais contribuer.

-(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
    }

}

Notez que pour appeler self.persistentStoreCoordinator, j'ai déclaré une propriété dans le Home View Controller. (Ne vous inquiétez pas du managedObjectContext que j'utilise pour l'enregistrement et le chargement.)

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

Ensuite, dans l'AppDelegate ApplicationDidFinishLaunching juste en dessous de la création d'un HomeViewController, j'ai:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;
un régal
la source
@ayteat, est-ce que cela a fonctionné pour vous ?. pour moi ça ne fonctionne pas, veuillez jeter un œil à ce stackoverflow.com/questions/14646595/…
Ranjit
1
CECI EST LA RÉPONSE, sauf utiliser "AppDelegate * ad = [[UIApplication sharedApplication] delegate];" et remplacez-vous par une annonce. et ne copiez pas les deux derniers bits de code
Cescy
1
Pourquoi n'appelez-vous pas reset sur managedObjectContext? Et si vous avez une référence forte à managedObject?
Parag Bafna
@ParagBafna Vous avez raison, l'exemple de code ci-dessus suppose qu'il n'y a pas de références fortes aux objets gérés. Si vous en avez, vous devriez envisager d'appeler «reset» sur le managedObjectContext et de déréférencer tous les objets gérés que vous avez.
traiter le
Hey, merci. De plus, existe-t-il un moyen de le faire lors de la mise à niveau de l'application? Pour être précis, mon exigence est lorsque je lance notre prochaine version de l'application, à ce moment-là, lorsque l'utilisateur met à jour son application depuis appStore, les fichiers de base n sqlite doivent être supprimés et réinitialisés pour être vides. J'ai trouvé un moyen de détecter le premier événement de lancement d'application en utilisant une valeur Bool dans NSUserDefaults et en vérifiant cette valeur dans didfinishLaunchingWithOptions du délégué de l'application, mais je n'ai pas compris comment effacer toutes ces choses. Puisqu'il n'y a pas de bouton et que le délégué de l'application ne détecte pas mon "persistentStore" pour l'effacer comme vous l'avez fait ci-dessus. de l'aide?
Tejas
19

MagicalRecord rend cela très facile.

[MyCoreDataObject MR_truncateAll];
Brian King
la source
16
c'est cool, mais hors sujet puisque j'ai spécifié une solution CoreData
Michael Grinich
8
La récupération active des enregistrements est une solution de données de base.
casademora
7
Mais une réponse comme celle-ci dépasse le cadre de la question. Il n'y a aucune raison de supposer qu'il souhaite utiliser un framework addt'l pour ce faire.
jpswain
Je dirais que cela ne répond pas à la question. C'est un bon moyen de supprimer des entrées d'une entité, pas de toutes les entités ...! Comment énumérer toutes les entités du modèle et les envoyer MR_truncateAll?
fatuhoku
Affichez la source de MR_truncateAll - il récupère tous les objets mais pas leurs propriétés (car nous avons l'intention de supprimer les NSMO), puis itère les objets de l'entité spécifiée et les supprime. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t
19

iOS9 +, Swift 2

Supprimer tous les objets dans toutes les entités

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)
        }
    }
}
Andres Wang
la source
1
Assurez-vous de voir pourquoi les entrées ne sont pas supprimées jusqu'à ce que l'application soit redémarrée ou que j'exécute ma NSBatchDeleteRequest deux fois? Longue histoire, le code ci-dessus n'est pas suffisant si les entités sont chargées dans la mémoire
Honey
13

[Réponse tardive en réponse à une prime demandant de nouvelles réponses]

En regardant les réponses précédentes,

  • La récupération et la suppression de tous les éléments, comme suggéré par @Grouchal et d'autres, est toujours une solution efficace et utile. Si vous avez de très grands magasins de données, cela peut être lent, mais cela fonctionne toujours très bien.
  • La simple suppression du magasin de données n'est plus, comme vous et @groundhog le notez, efficace. Il est obsolète même si vous n'utilisez pas de stockage binaire externe car iOS 7 utilise le mode WAL pour la journalisation SQLite. Avec le mode WAL, il peut y avoir des fichiers de journal (potentiellement volumineux) pour tout magasin persistant Core Data.

Mais il existe une approche différente et similaire pour supprimer le magasin persistant qui fonctionne. La clé est de placer votre fichier de stockage persistant dans son propre sous-répertoire qui ne contient rien d'autre. Ne vous contentez pas de le coller dans le répertoire des documents (ou n'importe où), créez un nouveau sous-répertoire juste pour le magasin persistant. Le contenu de ce répertoire finira par être le fichier de stockage persistant, les fichiers journaux et les fichiers binaires externes. Si vous souhaitez supprimer l'ensemble du magasin de données, supprimez ce répertoire et ils disparaîtront tous.

Vous feriez quelque chose comme ceci lors de la configuration de votre magasin persistant:

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...
}

Ensuite, lorsque vous avez voulu supprimer le magasin,

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

Cela supprime récursivement le sous-répertoire personnalisé et tous les fichiers Core Data qu'il contient.

Cela ne fonctionne que si vous n'avez pas déjà votre magasin persistant dans le même dossier que d'autres données importantes . Comme le répertoire des documents, qui contient probablement d'autres éléments utiles. Si tel est votre situation, vous pouvez obtenir le même effet en recherchant les fichiers que vous ne voulez garder et enlever tout le reste. Quelque chose comme:

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.
}

Cette approche peut être sujette aux erreurs . Vous devez être absolument sûr de connaître tous les fichiers que vous souhaitez conserver, sinon vous risquez de supprimer des données importantes. D'un autre côté, vous pouvez supprimer les fichiers binaires externes sans connaître le nom du fichier / répertoire utilisé pour les stocker.

Tom Harrington
la source
si vous avez peur du fichier wal, désactivez-le simplement
onmyway133
11

Voici une solution combinée pour purger les données de base.

- (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]);
        }
    }  
}
GxocT
la source
10

Si vous souhaitez supprimer tous les objets et ne souhaitez pas supprimer les fichiers de sauvegarde, vous pouvez utiliser les méthodes suivantes:

- (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);
    }
}

Attention, cela peut être très lent (cela dépend du nombre d'objets dans votre graphe d'objets).

Marián Černý
la source
comment supprimer les anciennes données (disons trois tables, à partir d'une table, je veux effacer les données) lorsque les mises à jour de l'application
Madan Mohan
6

Si vous souhaitez suivre la route Supprimer tous les objets (ce qui est beaucoup plus simple que de détruire la pile de Core Data, mais moins performant), c'est une meilleure implémentation:

- (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];
}

Cette implémentation s'appuie NSOperationpour effectuer la suppression du thread principal et notifier à la fin. Vous voudrez peut-être émettre une notification ou quelque chose dans le bloc d'achèvement pour faire remonter le statut au fil principal.

Blake Watters
la source
Notez que votre NSManagedObjectContext doit être initialisé comme NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];pour utiliser cette méthode, sinon vous obtenez l'erreur:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Will
6

Solution iOS 10 + Swift 3:

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()
        }
    }
}

Itère toutes les entités de données principales et les efface

KVISH
la source
4

Merci pour le post. Je l'ai suivi et cela a fonctionné pour moi. Mais j'avais un autre problème qui n'était mentionné dans aucune des réponses. Je ne sais donc pas si c'était juste moi.

Quoi qu'il en soit, j'ai pensé publier ici le problème et ma façon de le résoudre.

J'avais quelques enregistrements dans la base de données, je voulais tout purger avant d'écrire de nouvelles données dans la base de données, donc j'ai tout fait, y compris

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

puis utilisé managedObjectContextpour accéder à la base de données (censée être vide à ce jour), les données étaient toujours là. Après un certain temps de dépannage, je trouve que je dois réinitialiser managedObjectContext, managedObject, managedObjectModelet persistentStoreCoordinator, avant de l' utiliser managedObjectContextpour accéder au dabase. Maintenant, j'ai une base de données propre à écrire.

DanielZ
la source
Ainsi, la réinitialisation de managedObjectContext, managedObject, managedObjectModel et persistentStoreCoordinator remet le fichier contenant la base de données après sa suppression?
Daniel Brower
4

Voici une version quelque peu simplifiée avec moins d'appels à AppDelegate self et le dernier bit de code qui a été omis de la réponse la mieux notée. De plus, j'obtenais une erreur "Le magasin persistant de l'objet n'est pas accessible à partir du coordinateur de ce NSManagedObjectContext", il fallait donc juste l'ajouter à nouveau.

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];
}
Alberto Lopez
la source
4

solution rapide:

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)
    }
János
la source
Pour Swift 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido
3

Comme référence rapide pour enregistrer la recherche ailleurs - recréer le magasin persistant après sa suppression peut être fait avec:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
TimD
la source
J'ai essayé votre code, mais xcode lève une exception sur cette ligne, donc ce que vous avez à dire à ce sujet.
Ranjit
3

Plusieurs bonnes réponses à cette question. Voici une belle concise. Les deux premières lignes suppriment la base de données sqlite. Ensuite, la boucle for: supprime tous les objets de la mémoire managedObjectContext.

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];
}
adamek
la source
1
N'abusez
Michael Dorner
1
Je suis d'accord avec @MichaelDorner. Ajouter trop dans AppDelegate peut affecter les performances et gonfler la taille de votre binaire avec une toile d'araignée interconnectée de dépendances où AppDelegate doit soudainement être inclus dans chaque classe. Si vous trouvez cela surgir, créez un contrôleur séparé spécifique à cet effet. AppDelegate devrait rester pour l'initialisation de base et la gestion des changements d'état dans l'application, pas beaucoup plus.
jcpennypincher
2

vous pouvez également trouver tous les noms d'entités et les supprimer par leur nom. C'est une version plus longue mais fonctionne bien, de cette façon, vous n'avez pas à travailler avec le magasin de persistance

 - (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];
    }
}

pour "Any_Entity_Name" donnez simplement n'importe quel nom de votre entité, nous avons seulement besoin de comprendre la description de l'entité dans laquelle se trouvent vos entités. ValueForKey @ "nom" renverra tous les noms d'entité. Enfin, n'oubliez pas de sauvegarder.

Chris Lin
la source
2

La réponse acceptée est correcte avec la suppression de l'URL par NSFileManager est correcte, mais comme indiqué dans la modification iOS 5+, le magasin persistant n'est pas représenté uniquement par un fichier. Pour le magasin SQLite c'est * .sqlite, * .sqlite-shm et * .sqlite-wal ... heureusement depuis iOS 7+ nous pouvons utiliser la méthode

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: options: erreur:]

pour prendre soin de la suppression, le code devrait donc ressembler à ceci:

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];
JakubKnejzlik
la source
2
Vous devez transmettre les options dict, en particulier le nom du magasin, par exemple: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g
2

Voici une version qui supprime chaque enregistrement de chaque table que vous avez.

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)")
    }
}
Politta
la source
2

Swift 4/5, iOS 9+

La reconstruction de l'intégralité du CoreDatafichier SQLite garantira que toutes les données sont effacées, donc toutes les entités sont supprimées. Appelez 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()
    }
}
J. Doe
la source
pour tous ceux qui l'utilisent, notez qu'il va juste planter la "première fois" quand il n'y a pas de fichier sql là (j'ai juste utilisé un "garde" dans ma réponse)
Fattie
1

Fonctionne avec toutes les versions. Passez le nom de l'entité et parcourez pour supprimer toutes les entrées et enregistrer le contexte.

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)")
    }
}
Karun Kumar
la source
1

Une autre méthode (à part une demande de suppression de lot) que j'utilise souvent (en fonction des exigences de l'application) consiste à réinitialiser le magasin persistant. L'implémentation ressemble à ceci pour iOS 10+ et Swift (en supposant que vous avez une classe CoreDataManager):

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)
        }
    }

}

Un avantage de cette méthode est qu'elle est plus simple, surtout lorsque vous avez des charges d'enregistrement de données pour de nombreuses entités dans vos données de base. Dans ce cas, une demande de suppression de lot nécessiterait beaucoup de mémoire.

Oluwatobi Omotayo
la source
1

Solution Swift 5.1

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)
    }
}
Charlton Provatas
la source
0

Supprimer le fichier de magasin persistant et configurer un nouveau coordinateur de magasin persistant?

chasseur
la source
6
Heureusement, faire un nettoyage ne supprimera pas les fichiers de stockage persistants. Ce serait une recette de catastrophe si elle était vraie.
Hunter
0

Supprimez sqlite de votre fichierURLPath, puis générez.

I have
la source
Je voulais dire quand l'application est installée.
Michael Grinich
0

En supposant que vous utilisez MagicalRecordet avez un magasin de persistance par défaut:

Je n'aime pas toutes les solutions qui supposent que certains fichiers existent et / ou exigent la saisie des noms d'entités ou des classes. Il s'agit d'un Swift (2), un moyen sûr de supprimer toutes les données de toutes les entités. Après sa suppression, il recréera également une nouvelle pile (je ne sais pas vraiment à quel point cette pièce est nécessaire).

C'est godo pour les situations de style "déconnexion" lorsque vous voulez tout supprimer mais que vous avez un magasin de travail et un moc pour obtenir de nouvelles données (une fois que l'utilisateur se connecte ...)

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)
        }

    }
}
Aviel Gross
la source
0

Utilisez ceci

+(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];
}
Sandeep Singh
la source
0

J'ai pris le code de Grouchal et pour l'accélérer j'ai utilisé l'énumération avec le mode simultané ( NSEnumerationConcurrent), c'est devenu un peu plus rapide que pour la boucle (dans mon application, j'ai ajouté cette fonctionnalité pour les testeurs afin qu'ils puissent effacer les données et faire des tests plutôt que de supprimer et installer l'application)

- (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);
    }
}
anoop4real
la source
0

ici ma version swift3 pour supprimer tous les enregistrements. «Utilisateurs» est le nom de l'entité

@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
    }   
}
Kursat Turkay
la source