coredata - core data ios swift 4



Excluir/Redefinir todas as entradas no Core Data? (20)

Solução atualizada para iOS 9 ou superior

Use NSBatchDeleteRequest para excluir todos os objetos na entidade sem precisar carregá-los na memória ou iterar por eles.

// create the delete request for the specified entity
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "MyEntity")
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 foi atualizado para o iOS 10 e o Swift 3. Se você precisar oferecer suporte ao iOS 9, consulte esta pergunta .

Fontes:

https://src-bin.com

Você conhece alguma maneira de excluir todas as entradas armazenadas no Core Data? Meu esquema deve permanecer o mesmo; Eu só quero redefini-lo em branco.

Editar

Eu estou olhando para fazer isso de forma programática para que um usuário pode essencialmente acertar um botão de reset .


Answer #1

A resposta aceita está correta com a remoção de URL por NSFileManager está correto, mas como afirmado no iOS 5 + editar, o armazenamento persistente não é representado apenas por um arquivo. Para SQLite store é * .sqlite, * .sqlite-shm e * .sqlite-wal ... felizmente desde o iOS 7+ podemos usar o método

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: options: error:]

para cuidar da remoção, então o código deve ser algo assim:

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

Answer #2

Aqui está uma versão um pouco simplificada, com menos chamadas para AppDelegate self e o último bit de código que foi deixado de fora da resposta mais bem avaliada. Além disso, eu estava recebendo um erro "armazenamento persistente do objeto não é alcançável a partir deste coordenador do NSManagedObjectContext" por isso só precisava adicionar isso de volta.

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

Answer #3

Como uma referência rápida para salvar a pesquisa em outro lugar - recriar o armazenamento persistente após a exclusão pode ser feito com:

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

Answer #4

Eu peguei o código do Grouchal e para acelerar eu usei enumeração com o modo concorrente ( NSEnumerationConcurrent ), ele ficou um pouco mais rápido comparado ao for loop (no meu aplicativo eu adicionei esse recurso para o Testers para que eles pudessem limpar dados e fazer testcases ao invés de deletar e instalar o aplicativo)

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

Answer #5

Eu removo todos os dados dos dados do núcleo em um evento de botão em uma classe HomeViewController: Este artigo me ajudou muito e achei que iria contribuir.

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

}

Observe que, para chamar self.persistentStoreCoordinator, declarei uma propriedade no Home View Controller. (Não se preocupe com o managedObjectContext que eu uso para salvar e carregar.)

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

Então, no AppDelegate ApplicationDidFinishLaunching logo abaixo da criação de um HomeViewController eu tenho:

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

Answer #6

Excluir o arquivo de armazenamento persistente e configurar um novo coordenador de armazenamento persistente?


Answer #7

Funciona com todas as versões. Passe o nome da entidade e faça uma iteração para excluir todas as entradas e salvar o 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)")
    }
}

Answer #8

Se você quiser excluir todos os objetos e não quiser excluir os arquivos de apoio, poderá usar os seguintes 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);
    }
}

Tenha em atenção que pode ser muito lento (depende de quantos objetos existem no gráfico do objeto).


Answer #9

Se você quiser ir para a rota delete all objects (que é muito mais simples do que derrubar a pilha Core Data, mas com menos desempenho), então esta é uma implementação melhor:

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

Essa implementação aproveita NSOperation para executar a exclusão do thread principal e notificar na conclusão. Você pode querer emitir uma notificação ou algo dentro do bloco de conclusão para colocar o status de volta no thread principal.


Answer #10

Supondo que você esteja usando o MagicalRecord e tenha um armazenamento de persistência padrão:

Eu não gosto de todas as soluções que assumem certos arquivos para existir e / ou exigem a inserção de nomes ou classes de entidades. Esta é uma maneira segura de excluir todos os dados de todas as entidades. Após a exclusão, ela também recriará uma pilha nova (na verdade, não tenho certeza de como essa parte é necessária).

É godo para situações de estilo "logout" quando você deseja excluir tudo, mas tem um armazenamento de trabalho e moc para obter novos dados (uma vez que o usuário faz o login ...)

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

    }
}

Answer #11

Usa isto

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

Answer #12

Você ainda pode excluir o arquivo programaticamente, usando o 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];

Em seguida, basta adicionar o armazenamento persistente de volta para garantir que ele seja recriado corretamente.

A maneira programática de iterar por meio de cada entidade é mais lenta e propensa a erros. O uso para fazer isso dessa forma é se você quiser excluir algumas entidades e não outras. No entanto, você ainda precisa manter a integridade referencial ou não conseguirá persistir suas alterações.

Apenas remover a loja e recriá-la é rápido e seguro, e certamente pode ser feito de forma programática em tempo de execução.

Atualização para iOS5 +

Com a introdução do armazenamento binário externo (allowExternalBinaryDataStorage ou Store in External Record File) no iOS 5 e OS X 10.7, simplesmente excluir arquivos apontados por storeURLs não é suficiente. Você deixará os arquivos de registro externos para trás. Como o esquema de nomenclatura desses arquivos de registro externos não é público, ainda não tenho uma solução universal. - 8 de maio de 2012 às 23:00


Answer #13

Você pode excluir o arquivo SQLite - mas eu escolho fazer isso limpando as tabelas individualmente com uma função:

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

}

A razão pela qual eu escolhi fazer isso tabela por mesa é que isso me faz confirmar, já que estou fazendo a programação de que deletar o conteúdo da tabela é sensato e não há dados que eu prefira manter.

Fazê-lo esta vontade é muito mais lento do que apenas apagar o arquivo e vou mudar para uma exclusão de arquivo se este método demorar muito.


Answer #14

aqui minha versão swift3 para deletar todos os registros. 'Usuários' é o nome da entidade

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

Answer #15

iOS9 +, Swift 2

Excluir todos os objetos em todas as 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)
        }
    }
}

Answer #16

MagicalRecord torna isso muito fácil.

[MyCoreDataObject MR_truncateAll];

Answer #17

[Resposta tardia em resposta a uma recompensa pedindo novas respostas]

Olhando para as respostas anteriores,

  • Buscar e excluir todos os itens, como sugerido por @Grouchal e outros, ainda é uma solução eficaz e útil. Se você tiver armazenamentos de dados muito grandes, pode ser lento, mas ainda funciona muito bem.
  • Simplesmente remover o repositório de dados é, como você e @groundhog notam, não mais efetivo. Ele é obsoleto mesmo que você não use armazenamento binário externo porque o iOS 7 usa o modo WAL para o diário SQLite. Com o modo WAL, pode haver arquivos de diário (potencialmente grandes) em volta de qualquer armazenamento persistente de Core Data.

Mas há uma abordagem diferente e semelhante para remover o armazenamento persistente que funciona. A chave é colocar seu arquivo de armazenamento persistente em seu próprio subdiretório que não contém mais nada. Não basta colocá-lo no diretório de documentos (ou em qualquer outro lugar), crie um novo subdiretório apenas para o armazenamento persistente. O conteúdo desse diretório terminará sendo o arquivo de armazenamento persistente, os arquivos de diário e os arquivos binários externos. Se você quiser eliminar todo o armazenamento de dados, exclua esse diretório e todos eles desaparecerão.

Você faria algo assim ao configurar seu armazenamento 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...
}

Então, quando você quisesse remover a loja,

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

Isso recursivamente remove o subdiretório personalizado e todos os arquivos Core Data nele.

Isso só funciona se você ainda não tiver seu armazenamento persistente na mesma pasta que outros dados importantes . Como o diretório de documentos, que provavelmente tem outras coisas úteis nele. Se essa é a sua situação, você pode obter o mesmo efeito procurando por arquivos que deseja manter e removendo todo o resto. 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.
}

Essa abordagem pode ser propensa a erros . Você tem que ter absoluta certeza de que sabe todos os arquivos que deseja manter, porque senão você pode remover dados importantes. Por outro lado, você pode remover os arquivos binários externos sem realmente saber o nome do arquivo / diretório usado para armazená-los.


Answer #18

iOS 10 and Swift 3

Assuming that your entity name is "Photo", and that you create a CoreDataStack class...

 func clearData() {
        do {            
            let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo")
            do {
                let objects  = try context.fetch(fetchRequest) as? [NSManagedObject]
                _ = objects.map{$0.map{context.delete($0)}}
                CoreDataStack.sharedInstance.saveContext()
            } catch let error {
                print("ERROR DELETING : \(error)")
            }
        }
    }

Here is a good tutorial of how to use CoreData and how to use this method. https://medium.com/compileswift/parsing-json-response-and-save-it-in-coredata-step-by-step-fb58fc6ce16f#.1tu6kt8qb


Answer #19

you're all making this seem complicated. You can just send your NSManagedObjectContext the reset method





nsmanagedobject