Elimina / Reimposta tutte le voci in Dati principali?


235

Conosci un modo per eliminare tutte le voci memorizzate in Core Data? Il mio schema dovrebbe rimanere lo stesso; Voglio solo ripristinarlo in bianco.


modificare

Sto cercando di farlo a livello di codice in modo che un utente possa essenzialmente resetpremere un pulsante.


6
Molte delle risposte di seguito sono datate. Usa NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Possibile duplicato di dati
rapido

Risposte:


198

È comunque possibile eliminare il file a livello di codice, utilizzando il metodo NSFileManager: removeItemAtPath ::.

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

Quindi, aggiungi nuovamente il negozio persistente per assicurarti che venga ricreato correttamente.

Il modo programmatico per iterare attraverso ciascuna entità è sia più lento che soggetto a errori. L'uso per farlo in questo modo è se si desidera eliminare alcune entità e non altre. Tuttavia, devi comunque assicurarti di mantenere l'integrità referenziale o non sarai in grado di mantenere le modifiche.

Basta rimuovere il negozio e ricrearlo è sia veloce che sicuro e può certamente essere fatto programmaticamente in fase di esecuzione.

Aggiornamento per iOS5 +

Con l'introduzione dell'archiviazione binaria esterna (consenteExternalBinaryDataStorage o Store in External Record File) in iOS 5 e OS X 10.7, non è sufficiente eliminare semplicemente i file indicati da storeURL. Lascerai indietro i file dei record esterni. Poiché lo schema di denominazione di questi file di record esterni non è pubblico, non ho ancora una soluzione universale. - un 8 maggio 12 alle 23:00


1
Questa è probabilmente la migliore soluzione per l'affidabilità. Se volessi cancellare alcuni, ma non tutti i dati, vorrei utilizzare questo: stackoverflow.com/questions/1077810/...
Michael Grinich

12
So recuperare correttamente lo storeCoordinator. Tuttavia non so come ottenere il persistentStore. Quindi potresti per favore dare un esempio corretto invece che semplicemente: NSPersistentStore * store = ...;
Pascal Klein,

11
[[NSFileManager defaultManager] removeItemAtURL: storeURL error: & error] è migliore.
an0

3
@Pascal Se riesci a ottenere il coordinatore del negozio, puoi accedere a tutti i suoi negozi persistenti tramite la proprietà persistentStores.
Mihai Damian,

2
Codice di esempio che include come ricreare un nuovo negozio vuoto qui: stackoverflow.com/a/8467628
Joshua C. Lerner

140

È possibile eliminare il file SQLite - ma ho scelto di farlo eliminando le tabelle singolarmente con una funzione:

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

}

Il motivo per cui ho scelto di farlo tabella per tabella è che mi fa confermare mentre sto programmando che l'eliminazione del contenuto della tabella è ragionevole e non ci sono dati che preferirei conservare.

In questo modo sarà molto più lento della semplice eliminazione del file e passerò all'eliminazione di un file se questo metodo richiede troppo tempo.


Ottima soluzione Grazie. Che cos'è DLog ()?
Michael Grinich,

Ah sì - mi dispiace che sia una funzione speciale che uso solo un NSLog quando la build è una build DEBUG - basta sostituirla con NSLog.
Grouchal,

6
Puoi vedere un'implementazione di DLog qui: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long

3
Questo funziona bene per me. Ma per farlo andare più veloce, c'è un modo per eliminare tutti gli oggetti di una certa entità con un comando? Come in SQL, potresti fare qualcosa come DROP TABLE entity_name. Non voglio eliminare l'intero file SQL perché voglio solo eliminare tutti gli oggetti di un'entità specifica, non altre entità.
ma11hew28,

8
Usa NSDictionary * allEntities = _managedObjectModel.entitiesByName; per ottenere tutte le entità nel modello e quindi è possibile scorrere le chiavi in ​​questo NSDictionary per eliminare tutte le entità nel negozio.
adam0101,

60

Soluzione aggiornata per iOS 10+

Utilizzare NSBatchDeleteRequestper eliminare tutti gli oggetti nell'entità senza caricarli in memoria o scorrere attraverso di essi.

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

Questo codice è stato aggiornato per iOS 10 e Swift 3. Se devi supportare iOS 9, vedi questa domanda .

fonti:


3
Porrei che tutto il blocco all'interno di un moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect,

2
Assicurati di vedere Perché le voci non vengono eliminate fino a quando l'app non viene riavviata o non eseguo il mio NSBatchDeleteRequest due volte? Per farla breve, il codice sopra riportato NON è sufficiente se le entità vengono caricate in memoria
Honey,

38

Ho scritto un clearStoresmetodo che attraversa tutti i negozi ed eliminalo sia dal coordinatore che dal filesystem (gestione degli errori lasciata da parte):

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;

Questo metodo è all'interno di una coreDataHelperclasse che si occupa (tra l'altro) della creazione di persistentStore quando è nulla.


"nessun metodo di classe noto per il selettore 'persistentStores'"
Aviram Netanel

27

Rimuovo tutti i dati dai dati principali su un pulsante Evento in una classe HomeViewController: questo articolo mi ha aiutato così tanto che ho pensato che avrei contribuito.

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

}

Nota che per chiamare self.persistentStoreCoordinator ho dichiarato una proprietà nel controller Home View. (Non preoccuparti di managedObjectContext che utilizzo per il salvataggio e il caricamento.)

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

Quindi in AppDelegate ApplicationDidFinishLaunching proprio sotto la creazione di un HomeViewController ho:

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

@ayteat, ha funzionato per te ?. per me non funziona, per favore dai un'occhiata a questo stackoverflow.com/questions/14646595/…
Ranjit

1
QUESTA È LA RISPOSTA, tranne usare "AppDelegate * ad = [[UIApplication sharedApplication] delegato];" e sostituisci se stesso con l'annuncio. e non copiare gli ultimi due bit di codice
Cescy,

1
Perché non stai chiamando reset su managedObjectContext? Cosa succede se si ha un forte riferimento a managedObject?
Parag Bafna,

@ParagBafna Hai ragione, l'esempio di codice sopra presuppone che non ci siano riferimenti forti agli oggetti gestiti. Se ne hai alcuni, dovresti guardare chiamando 'reset' su managedObjectContext e de-fare riferimento a tutti gli oggetti gestiti che hai.
Tratti il

Ehi, grazie. Inoltre, c'è un modo per farlo sull'aggiornamento dell'app? Per essere precisi, il mio requisito è quando sto lanciando la nostra prossima versione di app, quella volta in cui l'utente aggiorna la sua app da appStore, i dati di base n i file sqlite dovrebbero essere eliminati e reinizializzati in bianco. Ho trovato il modo di rilevare l'evento di primo avvio dell'app usando un valore Bool in NSUserDefaults e controllando questo valore in didfinishLaunchingWithOptions del delegato dell'app, ma non ho capito come cancellare tutte queste cose. Poiché non è presente alcun pulsante e il delegato dell'app non rileva il mio "persistentStore" per cancellarlo come hai fatto sopra. qualsiasi aiuto?
Tejas,

19

MagicalRecord rende tutto molto semplice.

[MyCoreDataObject MR_truncateAll];

16
questo è bello, ma fuori tema da quando ho specificato una soluzione CoreData
Michael Grinich,

8
Active Record Fetching è una soluzione di dati di base.
casademora,

7
Ma una risposta come questa va oltre lo scopo della domanda. Non c'è motivo di presumere che voglia usare un framework aggiuntivo per farlo.
jpswain,

Direi che questo non risponde alla domanda. Questo è un buon modo per rimuovere le voci da un'entità, non tutte le entità ...! Come si elencano tutte le entità nel modello e le si inviano MR_truncateAll?
Fatuhoku,

Visualizza l'origine per MR_truncateAll: recupera tutti gli oggetti ma non le loro proprietà (poiché intendiamo scartare gli NSMO), quindi scorre gli oggetti per l'entità specificata e li elimina. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t

19

iOS9 +, Swift 2

Elimina tutti gli oggetti in tutte le entità

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
Assicurati di vedere Perché le voci non vengono eliminate fino a quando l'app non viene riavviata o non eseguo il mio NSBatchDeleteRequest due volte? Per farla breve il codice sopra riportato NON è sufficiente se le entità vengono caricate in memoria
Honey,

13

[Risposta tardiva in risposta a una generosità che richiede risposte più recenti]

Guardando le risposte precedenti,

  • Il recupero e l'eliminazione di tutti gli elementi, come suggerito da @Grouchal e altri, è ancora una soluzione efficace e utile. Se si dispone di archivi di dati molto grandi, potrebbe essere lento, ma funziona ancora molto bene.
  • La semplice rimozione dell'archivio dati, come notate tu e @groundhog, non è più efficace. È obsoleto anche se non si utilizza l'archiviazione binaria esterna perché iOS 7 utilizza la modalità WAL per il journaling di SQLite. Con la modalità WAL potrebbero esserci file journal (potenzialmente di grandi dimensioni) in giro per qualsiasi archivio persistente di Core Data.

Ma esiste un approccio diverso e simile per rimuovere l'archivio persistente che funziona. La chiave è mettere il tuo file di archivio persistente nella sua sottodirectory che non contiene nient'altro. Non limitarti a inserirlo nella directory dei documenti (o ovunque), crea una nuova sottodirectory solo per l'archivio permanente. Il contenuto di quella directory finirà per essere il file di archivio permanente, i file journal e i file binari esterni. Se si desidera eseguire il nuke dell'intero archivio dati, eliminare quella directory e scompariranno tutti.

Faresti qualcosa del genere quando imposti il ​​tuo negozio persistente:

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

Quindi, quando volevi rimuovere il negozio,

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

Ciò rimuove in modo ricorsivo sia la sottodirectory personalizzata che tutti i file Core Data in essa contenuti.

Funziona solo se non hai già il tuo archivio permanente nella stessa cartella di altri dati importanti . Come la directory dei documenti, che probabilmente contiene altre cose utili. Se questa è la vostra situazione, si potrebbe ottenere lo stesso effetto con la ricerca di file che non si desidera mantenere e la rimozione di tutto il resto. Qualcosa di simile a:

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

Questo approccio può essere soggetto a errori . Devi essere assolutamente sicuro di conoscere tutti i file che vuoi conservare, perché altrimenti potresti rimuovere dati importanti. D'altra parte, è possibile rimuovere i file binari esterni senza conoscere effettivamente il nome del file / directory utilizzato per memorizzarli.


se hai paura del file wal, disabilitalo
onmyway133

11

Ecco una soluzione combinata per l'eliminazione dei dati di 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]);
        }
    }  
}

10

Se si desidera eliminare tutti gli oggetti e non si desidera eliminare i file di backup, è possibile utilizzare i seguenti metodi:

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

Attenzione che potrebbe essere molto lento (dipende da quanti oggetti sono presenti nel grafico degli oggetti).


come rimuovere i dati più vecchi (diciamo tre tabelle, da una tabella voglio cancellare i dati) quando si aggiornano le app
Madan Mohan

6

Se vuoi andare sul percorso di eliminazione di tutti gli oggetti (che è molto più semplice che abbattere lo stack di dati principali, ma meno performante), questa è un'implementazione migliore:

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

Questa implementazione sfrutta NSOperationper eseguire la cancellazione dal thread principale e avvisare al completamento. Potresti voler emettere una notifica o qualcosa all'interno del blocco di completamento per riportare lo stato nel thread principale.


Si noti che NSManagedObjectContext deve essere inizializzato come NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];per utilizzare questo metodo altrimenti si ottiene l'errore:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Verrà

6

iOS 10 + soluzione 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()
        }
    }
}

Scorre tutte le entità di dati principali e le cancella


4

Grazie per il post. L'ho seguito e ha funzionato per me. Ma ho avuto un altro problema che non è stato menzionato in nessuna delle risposte. Quindi non sono sicuro che fossi solo io.

Comunque, ho pensato di pubblicare qui il problema e il mio modo di risolverlo.

Avevo alcuni record nel database, volevo eliminare tutto pulito prima di scrivere nuovi dati nel db, quindi ho fatto tutto incluso

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

e poi usato managedObjectContextper accedere al database (che ora dovrebbe essere vuoto), in qualche modo i dati erano ancora lì. Dopo un po 'di risoluzione dei problemi, ho scoperto che ho bisogno di resettare managedObjectContext, managedObject, managedObjectModele persistentStoreCoordinator, prima che io uso managedObjectContextper accedere al dabase. Ora ho un database pulito su cui scrivere.


Quindi reimpostare managedObjectContext, managedObject, managedObjectModel e persistentStoreCoordinator riporta il file contenente il database dopo che è stato eliminato?
Daniel Brower,

4

Ecco una versione in qualche modo semplificata con meno chiamate a AppDelegate self e l'ultimo bit di codice che è stato lasciato fuori dalla risposta più votata. Inoltre stavo ricevendo un errore "L'archivio persistente di Object non è raggiungibile da questo coordinatore di NSManagedObjectContext", quindi ho solo bisogno di aggiungerlo di nuovo.

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

soluzione rapida:

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

Per swift 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido,

3

Come rapido riferimento per salvare la ricerca altrove, è possibile ricreare l'archivio persistente dopo averlo eliminato con:

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

Ho provato il tuo codice, ma xcode genera un'eccezione su questa riga, quindi cosa hai da dire al riguardo.
Ranjit,

3

Diverse buone risposte a questa domanda. Eccone una concisa. Le prime due righe eliminano il database sqlite. Quindi il ciclo for: elimina tutti gli oggetti nella memoria 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];
}

1
Non abusare della delegazione per questo scopo: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner

1
Sono d'accordo con @MichaelDorner. L'aggiunta di molto in AppDelegate può influire sulle prestazioni e gonfiare le dimensioni del file binario con una ragnatela interconnessa di dipendenze in cui AppDelegate deve improvvisamente essere incluso in ogni classe. Se trovi questo ritaglio, crea un controller separato specifico per questo scopo. AppDelegate dovrebbe rimanere per l'inizializzazione di base e la gestione dei cambiamenti di stato nell'applicazione, non molto di più.
jcpennypincher,

2

puoi anche trovare tutti i nomi delle entità ed eliminarli per nome. È una versione più lunga ma funziona bene, in questo modo non devi lavorare con l'archivio di persistenza

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

per "Any_Entity_Name" basta dare uno qualsiasi del nome della tua entità, dobbiamo solo capire la descrizione dell'entità in cui si trovano le tue entità. ValueForKey @ "name" restituirà tutti i nomi delle entità. Infine, non dimenticare di salvare.


2

La risposta accettata è corretta con la rimozione dell'URL da NSFileManager è corretta, ma come indicato nella modifica di iOS 5+, l'archivio persistente non è rappresentato da un solo file. Per il negozio SQLite è * .sqlite, * .sqlite-shm e * .sqlite-wal ... fortunatamente da iOS 7+ possiamo usare il metodo

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: opzioni: errore:]

prendersi cura della rimozione, quindi il codice dovrebbe essere qualcosa del genere:

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
È necessario passare le opzioni dict, in particolare il nome del negozio, ad esempio: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g,

2

Ecco una versione che elimina ogni record in ogni tabella che hai.

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

2

Swift 4/5, iOS 9+

La ricostruzione dell'intero CoreDatafile SQLite farà in modo che tutti i dati vengano cancellati, quindi tutte le entità vengono eliminate. Chiama e basta 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()
    }
}

per chiunque usi questo, nota che andrà in crash la "prima volta" quando non ci sono file sql lì (ho appena usato una "guardia" nella mia risposta)
Fattie

1

Funziona con tutte le versioni. Passare il nome dell'entità e scorrere per eliminare tutte le voci e salvare il contesto.

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

Un altro metodo (a parte una richiesta di eliminazione batch) che utilizzo spesso (in base ai requisiti dell'app) è reimpostare l'archivio permanente. L'implementazione è simile a questa per iOS 10+ e Swift (supponendo che tu abbia una 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 vantaggio di questo metodo è che è più semplice soprattutto quando si hanno molti record di dati per numerose entità nei dati principali. Nel qual caso una richiesta batch di eliminazione richiederebbe molta memoria.


1

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

0

Eliminare il file di archivio persistente e impostare un nuovo coordinatore di archivio persistente?


6
Fare un clean non rimuoverà i file di archivio persistenti, per fortuna. Sarebbe una ricetta per il disastro se fosse vero.
Hunter,


0

Supponendo che tu stia utilizzando MagicalRecorde disponga di un archivio di persistenza predefinito:

Non mi piacciono tutte le soluzioni che presuppongono l'esistenza di determinati file e / o richiedono l'inserimento di nomi o classi di entità. Questo è un modo rapido (2), sicuro per eliminare tutti i dati da tutte le entità. Dopo averlo eliminato, verrà ricreato anche uno stack nuovo (in realtà non sono sicuro di quanto sia necessaria questa parte).

È godo per le situazioni di stile "logout" quando si desidera eliminare tutto ma si dispone di un archivio funzionante e moc per ottenere nuovi dati (una volta che l'utente accede ...)

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

Usa questo

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

Ho preso il codice di Grouchal e per accelerarlo ho usato l'enumerazione con modalità concorrente ( NSEnumerationConcurrent), è diventata un po 'più veloce rispetto a for loop (nella mia app ho aggiunto questa funzione per i tester in modo che possano cancellare i dati e fare testcase invece di eliminare e Installa l'applicazione)

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

qui la mia versione di swift3 per eliminare tutti i record. "Utenti" è il nome dell'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
    }   
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.