¿Eliminar / restablecer todas las entradas en los datos básicos?

235

¿Conoces alguna forma de eliminar todas las entradas almacenadas en Core Data? Mi esquema debería permanecer igual; Solo quiero restablecerlo en blanco.


Editar

Estoy buscando hacer esto programáticamente para que un usuario pueda presionar un resetbotón.

Michael Grinich
fuente
66
Muchas de las respuestas a continuación están fechadas. Uso NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Respuestas:

198

Todavía puede eliminar el archivo mediante programación, utilizando el método NSFileManager: removeItemAtPath ::.

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

Luego, simplemente agregue la tienda persistente para asegurarse de que se vuelva a crear correctamente.

La forma programática para iterar a través de cada entidad es más lenta y propensa a errores. El uso para hacerlo de esa manera es si desea eliminar algunas entidades y no otras. Sin embargo, aún debe asegurarse de conservar la integridad referencial o no podrá persistir en sus cambios.

Simplemente quitar la tienda y recrearla es rápido y seguro, y ciertamente se puede hacer programáticamente en tiempo de ejecución.

Actualización para iOS5 +

Con la introducción del almacenamiento binario externo (permite el almacenamiento externo de datos binarios o almacenar en un archivo de registro externo) en iOS 5 y OS X 10.7, simplemente eliminar archivos apuntados por storeURLs no es suficiente. Dejará los archivos de registro externos. Dado que el esquema de nombres de estos archivos de registro externos no es público, todavía no tengo una solución universal. - an0 8 de mayo de 12 a las 23:00

marmota
fuente
1
Esta es probablemente la mejor solución para la confiabilidad. Si quisiera eliminar algunos pero no todos los datos, usaría esto: stackoverflow.com/questions/1077810/…
Michael Grinich
12
Sé cómo recuperar correctamente el coordinador de la tienda. Sin embargo, no sé cómo obtener el persistentStore. Entonces, ¿podría dar un ejemplo adecuado en lugar de solo: NSPersistentStore * store = ...;
Pascal Klein
11
[[NSFileManager defaultManager] removeItemAtURL: storeURL error: & error] es mejor.
an0
3
@Pascal Si puede obtener el coordinador de la tienda, tendrá acceso a todas sus tiendas persistentes a través de la propiedad persistentStores.
Mihai Damian
2
Código de ejemplo que incluye cómo recrear una nueva tienda vacía aquí: stackoverflow.com/a/8467628
Joshua C. Lerner
140

Puede eliminar el archivo SQLite, pero elijo hacerlo purgando las tablas individualmente con funciones:

- (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 razón por la que elegí hacerlo tabla por tabla es porque me hace confirmar, mientras estoy haciendo la programación, que eliminar el contenido de la tabla es razonable y no hay datos que prefiera conservar.

Hacerlo es mucho más lento que simplemente eliminar el archivo y cambiaré a una eliminación de archivo si este método lleva demasiado tiempo.

Grouchal
fuente
Gran solución Gracias. ¿Qué es DLog ()?
Michael Grinich el
Ah sí, lo siento, es una función especial que uso que solo hace un NSLog cuando la compilación es una DEPURACIÓN, solo reemplácela con NSLog.
Grouchal 03 de
66
Puede ver una implementación de DLog aquí: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long
3
Esto funciona muy bien para mí. Pero para que sea más rápido, ¿hay alguna forma de eliminar todos los objetos de una determinada entidad con un solo comando? Al igual que en SQL, podría hacer algo como, DROP TABLE entity_name. No quiero eliminar todo el archivo SQL porque solo quiero eliminar todos los objetos de una entidad específica, no otras entidades.
ma11hew28
8
Use NSDictionary * allEntities = _managedObjectModel.entitiesByName; para obtener todas las entidades en su modelo y luego puede iterar sobre las claves en este NSDictionary para purgar todas las entidades en la tienda.
adam0101
60

Solución actualizada para iOS 10+

Se usa NSBatchDeleteRequestpara eliminar todos los objetos de la entidad sin tener que cargarlos en la memoria o iterar a través de ellos.

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

Este código se ha actualizado para iOS 10 y Swift 3. Si necesita admitir iOS 9, consulte esta pregunta .

Fuentes:

Suragch
fuente
3
Yo pondría todo ese bloque dentro de una moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect
2
Asegúrese de ver ¿Por qué las entradas no se eliminan hasta que se reinicia la aplicación o ejecuto mi NSBatchDeleteRequest dos veces? Larga historia, el código anterior NO es suficiente si las entidades se cargan en la memoria
Miel
38

He escrito un clearStoresmétodo que pasa por cada tienda y lo borra tanto del coordinador como del sistema de archivos (dejando de lado el manejo de errores):

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;

Este método está dentro de una coreDataHelperclase que se encarga (entre otras cosas) de crear persistentStore cuando es nulo.

samvermette
fuente
"no se conoce ningún método de clase para el selector 'persistentStores'"
Aviram Netanel
27

Elimino todos los datos de los datos centrales en un evento de botón en una clase HomeViewController: este artículo me ayudó tanto que pensé que contribuiría.

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

}

Tenga en cuenta que para llamar a self.persistentStoreCoordinator he declarado una propiedad en el Home View Controller. (No se preocupe por el ManageObjectContext que uso para guardar y cargar).

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

Luego, en AppDelegate ApplicationDidFinishLaunching justo debajo de crear un HomeViewController tengo:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;
Un dulce
fuente
@ayteat, ¿funcionó esto para ti? para mí no funciona, eche un vistazo a este stackoverflow.com/questions/14646595/…
Ranjit
1
ESTA ES LA RESPUESTA, excepto que use "AppDelegate * ad = [[UIApplication sharedApplication] delegate];" y reemplace self con anuncio. y no copie los dos últimos bits de código
Cescy
1
¿Por qué no está llamando a reset en managedObjectContext? ¿Qué sucede si tiene alguna referencia fuerte a managedObject?
Parag Bafna
@ParagBafna Tiene razón, el ejemplo de código anterior supone que no hay referencias fuertes a objetos administrados. Si tiene alguno, debe considerar llamar a 'reset' en managedObjectContext y desreferenciar cualquier objeto administrado que tenga.
atreat
Hey gracias. Además, ¿hay alguna forma de hacer esto en la actualización de la aplicación? Para ser precisos, mi requisito es cuando estoy lanzando nuestra próxima versión de la aplicación, esa vez cuando el usuario actualiza su aplicación desde appStore, los datos centrales y los archivos sqlite deben eliminarse y reinicializarse en blanco. Descubrí la forma de detectar el primer evento de inicio de la aplicación utilizando un valor Bool en NSUserDefaults y comprobando este valor en didfinishLaunchingWithOptions del delegado de la aplicación, pero no entendí cómo borrar todas estas cosas. Como no hay botón y el delegado de la aplicación no detecta mi "persistentStore" para borrarlo como lo hizo anteriormente. ¿alguna ayuda?
Tejas
19

MagicalRecord hace esto muy fácil.

[MyCoreDataObject MR_truncateAll];
Brian King
fuente
16
esto es genial, pero fuera de tema ya que especifiqué una solución CoreData
Michael Grinich
8
Active Record Fetching es una solución de datos básicos.
casademora
77
Pero una respuesta como esta va más allá del alcance de la pregunta. No hay razón para suponer que quiere usar un marco adicional para hacer esto.
jpswain
Yo diría que esto no responde la pregunta. ¡Esta es una buena manera de eliminar entradas de una entidad, no todas las entidades ...! ¿Cómo enumera a través de todas las entidades en el modelo y las envía MR_truncateAll?
fatuhoku
Vea el origen de MR_truncateAll: recupera todos los objetos pero no sus propiedades (ya que tenemos la intención de descartar las NSMO), luego itera sobre los objetos para la entidad especificada y los elimina. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t
19

iOS9 +, Swift 2

Eliminar todos los objetos en todas las entidades

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
fuente
1
Asegúrese de ver ¿Por qué las entradas no se eliminan hasta que se reinicia la aplicación o ejecuto mi NSBatchDeleteRequest dos veces? Larga historia, el código anterior NO es suficiente si las entidades se cargan en la memoria
Honey
13

[Respuesta tardía en respuesta a una recompensa pidiendo respuestas más nuevas]

Mirando las respuestas anteriores,

  • Obtener y eliminar todos los elementos, según lo sugerido por @Grouchal y otros, sigue siendo una solución efectiva y útil. Si tiene grandes almacenes de datos, puede ser lento, pero aún funciona muy bien.
  • Simplemente eliminar el almacén de datos ya no es efectivo, como notaron usted y @groundhog. Es obsoleto incluso si no usa almacenamiento binario externo porque iOS 7 usa el modo WAL para el diario de SQLite. Con el modo WAL puede haber archivos de diario (potencialmente grandes) para cualquier tienda persistente de Core Data.

Pero hay un enfoque diferente y similar para eliminar la tienda persistente que funciona. La clave es colocar su archivo de almacenamiento persistente en su propio subdirectorio que no contiene nada más. No lo pegue en el directorio de documentos (o donde sea), cree un nuevo subdirectorio solo para la tienda persistente. El contenido de ese directorio terminará siendo el archivo de almacenamiento persistente, los archivos de diario y los archivos binarios externos. Si desea destruir todo el almacén de datos, elimine ese directorio y todos desaparecerán.

Haría algo como esto al configurar su tienda 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...
}

Luego, cuando quisiste eliminar la tienda,

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

Eso elimina de forma recursiva tanto el subdirectorio personalizado como todos los archivos de Core Data que contiene.

Esto solo funciona si aún no tiene su tienda persistente en la misma carpeta que otros datos importantes . Al igual que el directorio de documentos, que probablemente tiene otras cosas útiles. Si ese es su caso, usted podría conseguir el mismo efecto mediante la búsqueda de archivos que no desee conservar y eliminar todo lo demás. Algo como:

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

Este enfoque puede ser propenso a errores . Debe estar absolutamente seguro de conocer todos los archivos que desea conservar, ya que de lo contrario podría eliminar datos importantes. Por otro lado, puede eliminar los archivos binarios externos sin saber realmente el nombre del archivo / directorio utilizado para almacenarlos.

Tom Harrington
fuente
si tienes miedo del archivo wal, deshabilítalo
onmyway133
11

Aquí hay una solución combinada para purgar los datos principales.

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

Si desea eliminar todos los objetos y no desea eliminar los archivos de respaldo, puede utilizar los siguientes métodos:

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

Tenga en cuenta que puede ser muy lento (depende de cuántos objetos haya en su gráfico de objetos).

Marián Černý
fuente
cómo eliminar los datos más antiguos (digamos tres tablas, de una tabla quiero borrar los datos) cuando las actualizaciones de la aplicación
Madan Mohan
6

Si desea ir a la ruta de eliminar todos los objetos (que es mucho más simple que derribar la pila de Core Data, pero menos eficiente), entonces esta es una mejor implementación:

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

Esta implementación aprovecha NSOperationpara realizar la eliminación del hilo principal y notificar al finalizar. Es posible que desee emitir una notificación o algo dentro del bloque de finalización para que el estado vuelva al hilo principal.

Blake Watters
fuente
Tenga en cuenta que su NSManagedObjectContext debe inicializarse como NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];para poder usar este método o de lo contrario obtendrá el error:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Será el
6

Solución 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()
        }
    }
}

Itera a través de todas las entidades de datos centrales y las borra

KVISH
fuente
4

Gracias por la publicacion. Lo seguí y funcionó para mí. Pero tuve otro problema que no se mencionó en ninguna de las respuestas. Así que no estoy seguro si solo fui yo.

De todos modos, pensé que publicaría aquí el problema y mi forma de resolverlo.

Tenía algunos registros en la base de datos, quería limpiar todo antes de escribir nuevos datos en la base de datos, así que hice todo, incluido

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

y luego solía managedObjectContextacceder a la base de datos (se suponía que ya estaba vacía), de alguna manera los datos todavía estaban allí. Después de un tiempo de resolución de problemas, he encontrado que tengo que reiniciar managedObjectContext, managedObject, managedObjectModely persistentStoreCoordinator, antes de que yo utilizo managedObjectContextpara acceder a la dabase. Ahora tengo una base de datos limpia para escribir.

DanielZ
fuente
Entonces, ¿al restablecer managedObjectContext, managedObject, managedObjectModel y persistentStoreCoordinator pone el archivo que contiene la base de datos nuevamente después de que se haya eliminado?
Daniel Brower
4

Aquí hay una versión algo simplificada con menos llamadas a AppDelegate self y el último fragmento de código que quedó fuera de la respuesta mejor calificada. También recibí un error "No se puede acceder al almacén persistente del objeto desde este coordinador de NSManagedObjectContext", por lo que solo necesito agregarlo nuevamente.

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
fuente
4

solución rápida:

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
fuente
Para let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Swift
3

Como referencia rápida para guardar la búsqueda en otro lugar, puede volver a crear la tienda persistente después de eliminarla con:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
TimD
fuente
Probé su código, pero xcode arroja una excepción en esta línea, así que lo que tiene que decir sobre esto.
Ranjit
3

Varias buenas respuestas a esta pregunta. Aquí hay una buena y concisa. Las dos primeras líneas eliminan la base de datos sqlite. Luego, el bucle for: elimina todos los objetos en la 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];
}
adamek
fuente
1
No abuse de la delegación para este propósito: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner
1
Estoy de acuerdo con @MichaelDorner. Agregar mucho a AppDelegate puede afectar el rendimiento y aumentar el tamaño de su binario con una telaraña interconectada de dependencias donde AppDelegate de repente necesita ser incluido en cada clase. Si encuentra este recorte, cree un controlador separado específico para este propósito. AppDelegate debe permanecer para la inicialización básica y manejar los cambios de estado en la aplicación, no mucho más.
jcpennypincher
2

También puede encontrar todos los nombres de entidad y eliminarlos por nombre. Es una versión más larga pero funciona bien, de esa manera no tienes que trabajar con la tienda de persistencia

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

para "Any_Entity_Name" solo proporcione el nombre de cualquiera de su entidad, solo necesitamos averiguar la descripción de la entidad dentro de la cual se encuentran sus entidades. ValueForKey @ "name" devolverá todos los nombres de entidad. Finalmente, no olvides guardar.

Chris Lin
fuente
2

La respuesta aceptada es correcta con la eliminación de URL por NSFileManager es correcta, pero como se indica en iOS 5+ edit, la tienda persistente no está representada solo por un archivo. Para la tienda SQLite es * .sqlite, * .sqlite-shm y * .sqlite-wal ... afortunadamente desde iOS 7+ podemos usar el método

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: opciones: error:]

para cuidar la eliminación, por lo que el código debería ser algo como esto:

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
fuente
2
Debe pasar las opciones dict, en particular el nombre de la tienda, por ejemplo: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g
2

Aquí hay una versión que elimina todos los registros en cada tabla que tiene.

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
fuente
2

Swift 4/5, iOS 9+

Reconstruir todo el CoreDataarchivo SQLite asegurará que se borren todos los datos, por lo tanto, se eliminarán todas las entidades. Solo llama 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
fuente
para cualquiera que use esto, tenga en cuenta que simplemente se bloqueará la "primera vez" cuando no haya un archivo sql allí (solo usé un "guardia" en mi respuesta)
Fattie
1

Funciona con todas las versiones. Pase el nombre de la entidad e itere para eliminar todas las entradas y guardar el contexto.

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
fuente
1

Otro método (aparte de una solicitud de eliminación de lotes) que uso a menudo (según los requisitos de la aplicación) es restablecer el almacén persistente. La implementación se ve así para iOS 10+ y Swift (suponiendo que tenga una clase 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)
        }
    }

}

Una ventaja de este método es que es más sencillo, especialmente cuando tiene un montón de registros de datos para numerosas entidades en sus datos principales. En cuyo caso, una solicitud de eliminación por lotes requeriría mucha memoria.

Oluwatobi Omotayo
fuente
1

Solución 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
fuente
0

¿Eliminar el archivo de tienda persistente y configurar un nuevo coordinador de tienda persistente?

Cazador
fuente
66
Hacer una limpieza no eliminará los archivos de almacenamiento persistentes, afortunadamente. Esa sería una receta para el desastre si es cierto.
Hunter
0

Elimine sqlite de su fileURLPath y luego compile.

Jai
fuente
Quise decir cuando la aplicación está instalada.
Michael Grinich
0

Suponiendo que está utilizando MagicalRecordy tiene un almacén de persistencia predeterminado:

No me gustan todas las soluciones que suponen que existen ciertos archivos y / o exigen ingresar los nombres o clases de las entidades. Esta es una manera segura (2) de Swift para eliminar todos los datos de todas las entidades. Después de eliminarlo, también recreará una pila nueva (en realidad no estoy seguro de cuán necesaria es esta parte).

Es un godo para situaciones de estilo de "cierre de sesión" cuando desea eliminar todo pero tiene un almacén y un moc en funcionamiento para obtener nuevos datos (una vez que el usuario inicia sesión ...)

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
fuente
0

Utilizar este

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

Tomé el código de Grouchal y, para acelerarlo, utilicé la enumeración con el modo concurrente ( NSEnumerationConcurrent), se hizo un poco más rápido en comparación con for loop (en mi aplicación agregué esta función para los Probadores para que puedan borrar datos y hacer casos de prueba en lugar de eliminar y instalar aplicación)

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

Aquí mi versión swift3 para eliminar todos los registros. 'Usuarios' es el nombre de la entidad

@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
fuente