Excluir / redefinir todas as entradas nos dados principais?

235

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

Estou procurando fazer isso programaticamente, para que um usuário possa essencialmente pressionar um resetbotão.

Michael Grinich
fonte
6
Muitas das respostas abaixo estão datadas. Use NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Respostas:

198

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, adicione novamente o armazenamento persistente para garantir que ele seja recriado corretamente.

A maneira programática de iterar através de cada entidade é mais lenta e propensa a erros. O uso para fazer dessa maneira é se você deseja excluir algumas entidades e outras não. No entanto, você ainda precisa garantir a integridade referencial ou não poderá persistir nas alterações.

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

Atualização para iOS5 +

Com a introdução do armazenamento binário externo (permiteExternalBinaryDataStorage 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 nomeação desses arquivos de registro externos não é público, ainda não tenho uma solução universal. - an0 8 / mai / 12 às 23:00

marmota
fonte
1
Esta é provavelmente a melhor solução para confiabilidade. Se eu quisesse excluir alguns, mas não todos os dados, gostaria de usar isso: stackoverflow.com/questions/1077810/...
Michael Grinich
12
Eu sei como recuperar corretamente a storeCoordinator. No entanto, eu não sei como obter o persistentStore. Então, você poderia dar um exemplo adequado em vez de apenas: NSPersistentStore * store = ...;
Pascal Klein
11
[[NSFileManager defaultManager] removeItemAtURL: erro da storeURL: & error] é melhor.
an0
3
@ Pascal Se você puder obter o coordenador da loja, terá acesso a todas as suas lojas persistentes por meio da propriedade persistentStores.
Mihai Damian
2
Código de exemplo, incluindo como recriar uma nova loja vazia aqui: stackoverflow.com/a/8467628
Joshua C. Lerner
140

Você pode excluir o arquivo SQLite - mas eu escolho fazê-lo limpando as tabelas individualmente com as seguintes funções:

- (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 escolhi fazê-lo tabela por tabela é que isso me faz confirmar, enquanto estou fazendo a programação, que a exclusão do conteúdo da tabela é sensata e não há dados que eu prefira manter.

Fazer isso será muito mais lento do que apenas excluir o arquivo e mudarei para uma exclusão de arquivo se esse método demorar muito.

Grouchal
fonte
Ótima solução. Obrigado. O que é o DLog ()?
22611 Michael Grinich
Ah, sim - desculpe, é uma função especial que eu uso que apenas faz um NSLog quando a compilação é uma compilação DEBUG - basta substituir pelo NSLog.
Grouchal
6
Você pode ver uma implementação de DLoG aqui: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt longas
3
Isso funciona muito bem para mim. Mas, para acelerar, existe uma maneira de excluir todos os objetos de uma determinada entidade com um comando? Como no SQL, você poderia fazer algo como DROP TABLE entity_name. Não quero excluir o arquivo SQL inteiro porque quero excluir todos os objetos de uma entidade específica, não de outras entidades.
precisa saber é o seguinte
8
Use NSDictionary * allEntities = _managedObjectModel.entitiesByName; para obter todas as entidades em seu modelo e, em seguida, você pode percorrer as chaves neste NSDictionary para limpar todas as entidades na loja.
22412 adam0101
60

Solução atualizada para iOS 10+

Use NSBatchDeleteRequestpara excluir todos os objetos na entidade sem precisar carregá-los na memória ou iterá-los.

// 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 foi atualizado para iOS 10 e Swift 3. Se você precisar oferecer suporte ao iOS 9, consulte esta pergunta .

Fontes:

Suragch
fonte
3
Eu colocaria esse bloco inteiro dentro de um moc.performBlockAndWait({ () -> Void in...}) .
SwiftArchitect
2
Verifique por que as entradas não são excluídas até que o aplicativo seja reiniciado ou que eu execute meu NSBatchDeleteRequest duas vezes? Para uma longa história, o código acima NÃO será suficiente se as entidades forem carregadas na memória
Honey
38

Escrevi um clearStoresmétodo que percorre todas as lojas e o excluo do coordenador e do sistema de arquivos (tratamento de erros deixado de lado):

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;

Esse método está dentro de uma coreDataHelperclasse que cuida (entre outras coisas) da criação do persistentStore quando é nulo.

samvermette
fonte
"nenhum método de classe conhecido para o seletor 'persistentStores'"
Aviram Netanel 14/06/2015
27

Eu removo todos os dados dos dados principais de um evento de botão em uma classe HomeViewController: Este artigo me ajudou tanto que achei que contribuiria.

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

Em seguida, no AppDelegate ApplicationDidFinishLaunching logo abaixo, crie um HomeViewController que tenho:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;
uma ameaça
fonte
@ayteat, isso funcionou para você? para mim não está funcionando, por favor, dê uma olhada neste stackoverflow.com/questions/14646595/…
Ranjit
1
ESTA É A RESPOSTA, exceto o uso "AppDelegate * ad = [[UIApplication sharedApplication] delegate];" e substitua self por ad. e não faça copiar últimos dois pedaços de código
Cescy
1
Por que você não está chamando reset no managedObjectContext? E se você tiver alguma referência forte ao managedObject?
Parag Bafna
@ParagBafna Você está correto, o exemplo de código acima pressupõe que não há referências fortes a objetos gerenciados. Se você tiver algum, deve chamar 'reset' no managedObjectContext e desassociar qualquer objeto gerenciado que você tenha.
atreat
Ei, obrigado. Além disso, existe alguma maneira de fazer isso na atualização do aplicativo? Para ser mais preciso, meu requisito é que quando estiver lançando nossa próxima versão do aplicativo, quando o usuário atualize seu aplicativo da appStore, os principais dados e arquivos sqlite devem ser excluídos e reinicializados para ficar em branco. Eu descobri uma maneira de detectar o primeiro evento de inicialização do aplicativo usando um valor Bool em NSUserDefaults e verificando esse valor no didfinishLaunchingWithOptions do delegado do aplicativo, mas não entendi como limpar todas essas coisas. Como não há botão e o representante do aplicativo não está detectando minha "persistentStore" para limpá-la, como você fez acima. qualquer ajuda?
Tejas 14/10
19

O MagicalRecord torna isso muito fácil.

[MyCoreDataObject MR_truncateAll];
Brian King
fonte
16
isso é legal, mas fora do assunto desde que eu especificado uma solução CoreData
Michael Grinich
8
A busca ativa de registros é uma solução de dados principal.
casademora
7
Mas uma resposta como essa vai além do escopo da pergunta. Não há razão para supor que ele queira usar uma estrutura adicional para fazer isso.
Jspwain
Eu diria que isso não responde à pergunta. Esta é uma boa maneira de remover entradas de uma entidade, nem todas as entidades ...! Como você enumera através de todas as entidades no modelo e as envia MR_truncateAll?
fatuhoku 7/08/14
Veja a fonte para MR_truncateAll - ele busca todos os objetos, mas não suas propriedades (como pretendemos descartar os NSMOs), depois itera sobre os objetos da entidade especificada e os exclui. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t 23/10/16
19

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)
        }
    }
}
Andres Wang
fonte
1
Certifique-se de ver Por que as entradas não são excluídas até que o aplicativo seja reiniciado ou que eu execute meu NSBatchDeleteRequest duas vezes? Longa história o código acima não é suficiente , se as entidades são carregados na memória
Mel
13

[Resposta tardia em resposta a uma recompensa pedindo respostas mais recentes]

Examinando respostas anteriores,

  • Buscar e excluir todos os itens, conforme 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 armazenamento de dados é, como você e o @groundhog observam, não é mais eficaz. É obsoleto mesmo se você não usar armazenamento binário externo, porque o iOS 7 usa o modo WAL para diário de SQLite. No modo WAL, pode haver arquivos de diário (potencialmente grandes) disponíveis para qualquer armazenamento persistente do 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 o cole 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 acabará sendo o arquivo de armazenamento persistente, os arquivos de diário e os arquivos binários externos. Se você quiser destruir o repositório de dados inteiro, exclua esse diretório e todos eles desaparecerão.

Você faria algo assim ao configurar sua loja 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ê quis remover a loja,

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

Isso remove recursivamente o subdiretório personalizado e todos os arquivos de dados principais nele.

Isso funciona apenas se você ainda não possui seu armazenamento persistente na mesma pasta que outros dados importantes . Como o diretório de documentos, que provavelmente possui outras coisas úteis. Se essa é a sua situação, você pode obter o mesmo efeito, procurando por arquivos que você não deseja manter e remover tudo 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 estar sujeita a erros . Você precisa ter certeza absoluta de que conhece todos os arquivos que deseja manter, pois, caso contrário, poderá remover dados importantes. Por outro lado, você pode remover os arquivos binários externos sem saber o nome do arquivo / diretório usado para armazená-los.

Tom Harrington
fonte
se você tem medo do arquivo wal, apenas desativá-lo
onmyway133
11

Aqui está a solução combinada para limpar os Dados Principais.

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

Se você deseja excluir todos os objetos e não deseja excluir os arquivos de backup, pode 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);
    }
}

Cuidado, pois pode ser muito lento (depende de quantos objetos estão no seu gráfico de objetos).

Marián Černý
fonte
como remover os dados mais antigos (dizer três tabelas, a partir de uma tabela que eu quero de dados claro) quando as atualizações de aplicativos
Madan Mohan
6

Se você deseja ir para a rota excluir todos os objetos (que é muito mais simples do que derrubar a pilha de dados principais, mas com menos desempenho), é 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 NSOperationa exclusão do encadeamento principal e a notificação na conclusão. Convém emitir uma notificação ou algo dentro do bloco de conclusão para retornar o status ao segmento principal.

Blake Watters
fonte
Observe que seu NSManagedObjectContext deve ser inicializado como NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];para usar esse método, ou então você recebe o erro:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Será
6

Solução 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()
        }
    }
}

Repete todas as entidades de dados principais e as limpa

KVISH
fonte
4

Obrigado pelo post. Eu o segui e funcionou para mim. Mas tive outro problema que não foi mencionado em nenhuma das respostas. Então, eu não tenho certeza se era apenas eu.

Enfim, pensei em postar aqui o problema e meu jeito de resolvê-lo.

Eu tinha alguns registros no banco de dados, queria limpar tudo antes de gravar novos dados no banco de dados, então fiz tudo, incluindo

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

e então usado managedObjectContextpara acessar o banco de dados (que deveria estar vazio agora), de alguma forma os dados ainda estavam lá. Depois de um tempo de resolução de problemas, eu descobri que eu preciso redefinir managedObjectContext, managedObject, managedObjectModele persistentStoreCoordinator, antes de eu usar managedObjectContextpara acessar o dabase. Agora eu tenho um banco de dados limpo para escrever.

DanielZ
fonte
Portanto, a redefinição de managedObjectContext, managedObject, managedObjectModel e persistentStoreCoordinator coloca o arquivo que contém o banco de dados novamente após ser excluído?
Daniel Brower
4

Aqui está uma versão um pouco simplificada, com menos chamadas para o AppDelegate e o último pedaço de código que foi deixado de fora da resposta mais votada. Também estava recebendo um erro "O armazenamento persistente do objeto não está acessível a partir deste coordenador do NSManagedObjectContext", portanto, era necessário apenas adicioná-lo novamente.

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

solução 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
fonte
Para swift 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido
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
}
TimD
fonte
Eu tentei o seu código, mas o xcode lança uma exceção nesta linha, então o que você tem a dizer sobre isso.
Ranjit
3

Várias boas respostas para esta pergunta. Aqui está um bom e conciso. As duas primeiras linhas excluem o banco de dados sqlite. Em seguida, o loop for: exclui todos os objetos na memória 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
fonte
1
Não abuse a delegação para essa finalidade: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner
1
Eu concordo com @MichaelDorner. Adicionar muito ao AppDelegate pode afetar o desempenho e aumentar o tamanho do seu binário com uma teia de aranha interconectada de dependências, onde o AppDelegate de repente precisa ser incluído em todas as classes. Se você descobrir isso, crie um controlador separado específico para esse fim. O AppDelegate deve permanecer para inicialização básica e manipulação de alterações de estado no aplicativo, não muito mais.
Jcpennypincher 17/07/2015
2

você também pode encontrar todos os nomes de entidades e excluí-los por nome. É uma versão mais longa, mas funciona bem, assim você não precisa trabalhar com armazenamento de persistência

 - (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" forneça apenas o nome da sua entidade, precisamos apenas descobrir a descrição da entidade em que elas estão. ValueForKey @ "name" retornará todos os nomes de entidade. Finalmente, não se esqueça de salvar.

Chris Lin
fonte
2

A resposta aceita está correta, com a remoção do URL pelo NSFileManager, mas conforme declarado na edição iOS 5+, o armazenamento persistente não é representado apenas por um arquivo. Para a loja SQLite, é * .sqlite, * .sqlite-shm e * .sqlite-wal ... felizmente, desde o iOS 7+, podemos usar o método

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: opções: erro:]

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

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
fonte
2
Você precisa passar o ditado das opções, em particular o nome da loja, por exemplo: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g
2

Aqui está uma versão que exclui todos os registros em todas as tabelas que você possui.

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

Swift 4/5, iOS 9 ou superior

A reconstrução de todo o CoreDataarquivo SQLite garantirá que todos os dados sejam apagados, portanto, todas as entidades serão excluídas. Basta ligar 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
fonte
para quem usa isso, observe que ele travará na "primeira vez" quando não houver arquivo sql (usei um "protetor" na minha resposta)
Fattie 03/02
1

Funciona com todas as versões. Passe o nome da entidade e percorra 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)")
    }
}
Karun Kumar
fonte
1

Um outro método (além de uma solicitação de exclusão em lote) que geralmente uso (com base nos requisitos do aplicativo) é redefinir o armazenamento persistente. A implementação é assim para iOS 10+ e Swift (supondo que você tenha uma 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)
        }
    }

}

Uma vantagem desse método é que é mais direto, especialmente quando você tem um monte de registros de dados para várias entidades em seus dados principais. Nesse caso, uma solicitação de exclusão em lote exigiria muita memória.

Oluwatobi Omotayo
fonte
1

Solução 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
fonte
0

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

Caçador
fonte
6
Fazer uma limpeza não removerá os arquivos de armazenamento persistente, felizmente. Isso seria uma receita para o desastre, se verdadeiro.
Hunter
0

Exclua o sqlite do seu fileURLPath e construa.

Jai
fonte
Eu quis dizer quando o aplicativo está instalado.
22811 Michael Grinich
0

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

Não gosto de todas as soluções que supõem que certos arquivos existem e / ou exigem a inserção de nomes ou classes de entidades. Esta é uma maneira rápida e segura de excluir todos os dados de todas as entidades. Após a exclusão, ele também recriará uma pilha nova (na verdade, não tenho certeza de quão necessário é essa parte).

É ideal para situações no estilo "logout" quando você deseja excluir tudo, mas possui um repositório de trabalho e um moc para obter novos dados (uma vez que o usuário efetua 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)
        }

    }
}
Aviel Gross
fonte
0

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];
}
Sandeep Singh
fonte
0

Peguei o código de Grouchal e, para acelerar, usei a enumeração no modo simultâneo ( NSEnumerationConcurrent), ficou um pouco mais rápido em comparação ao loop for (no meu aplicativo, adicionei esse recurso aos testadores para que eles possam limpar dados e fazer testes, em vez de excluir e instalar 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);
    }
}
anoop4real
fonte
0

aqui minha versão swift3 para excluir 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
    }   
}
Kursat Turkay
fonte