Usunąć / zresetować wszystkie wpisy w podstawowych danych?

235

Czy znasz sposób na usunięcie wszystkich wpisów przechowywanych w podstawowych danych? Mój schemat powinien pozostać taki sam; Chcę tylko zresetować go do stanu pustego.


Edytować

Chcę to zrobić programowo, aby użytkownik mógł w zasadzie nacisnąć resetprzycisk.

Michael Grinich
źródło
6
Wiele poniższych odpowiedzi jest datowanych. Zastosowanie NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch,

Odpowiedzi:

198

Nadal możesz usunąć plik programowo, używając metody NSFileManager: removeItemAtPath ::

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

Następnie po prostu dodaj z powrotem trwały sklep, aby upewnić się, że jest on poprawnie odtwarzany.

Programowy sposób iteracji przez każdą jednostkę jest zarówno wolniejszy, jak i podatny na błędy. Wykorzystanie tego w ten sposób ma miejsce, jeśli chcesz usunąć niektóre podmioty, a nie inne. Jednak nadal musisz upewnić się, że zachowałeś integralność referencyjną, w przeciwnym razie nie będziesz w stanie utrzymać swoich zmian.

Samo usunięcie sklepu i jego ponowne utworzenie jest szybkie i bezpieczne, a na pewno można to zrobić programowo w czasie wykonywania.

Aktualizacja dla iOS5 +

Wraz z wprowadzeniem zewnętrznej pamięci binarnej (pozwalaExternalBinaryDataStorage lub Zapisz w zewnętrznym pliku rekordu) w iOS 5 i OS X 10.7, samo usunięcie plików wskazanych przez storeURLs nie wystarczy. Zostawisz zewnętrzne pliki nagrań. Ponieważ schemat nazewnictwa tych zewnętrznych plików rekordów nie jest publiczny, nie mam jeszcze uniwersalnego rozwiązania. - 0 maja 8 '12 o 23:00

świstak
źródło
1
Jest to prawdopodobnie najlepsze rozwiązanie pod względem niezawodności. Gdybym chciał usunąć niektóre, ale nie wszystkie dane, chciałbym skorzystać z tego: stackoverflow.com/questions/1077810/...
Michael Grinich
12
Wiem, jak prawidłowo odzyskać koordynatora sklepu. Jednak nie wiem, jak uzyskać trwały sklep. Czy mógłbyś więc podać właściwy przykład zamiast: NSPersistentStore * store = ...;
Pascal Klein
11
[[NSFileManager defaultManager] removeItemAtURL: błąd storeURL: i błąd] jest lepszy.
an0
3
@Pascal Jeśli możesz uzyskać koordynatora sklepu, będziesz mieć dostęp do wszystkich jego stałych sklepów za pośrednictwem właściwości persistentStores.
Mihai Damian
2
Przykładowy kod, w tym jak odtworzyć nowy pusty sklep tutaj: stackoverflow.com/a/8467628
Joshua C. Lerner
140

Możesz usunąć plik SQLite - ale ja wybieram to, usuwając tabele indywidualnie za pomocą funkcji:

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

}

Powodem, dla którego zdecydowałem się zrobić to tabela po tabeli, jest to, że w trakcie programowania potwierdzam, że usunięcie zawartości tabeli jest sensowne i nie ma danych, które wolałbym przechowywać.

Zrobienie tego będzie znacznie wolniejsze niż samo usunięcie pliku, a ja zmienię na usunięcie pliku, jeśli ta metoda potrwa zbyt długo.

Grouchal
źródło
Świetne rozwiązanie. Dzięki. Co to jest DLog ()?
Michael Grinich
Ach tak - przepraszam, to specjalna funkcja, której używam, która wykonuje NSLog tylko wtedy, gdy kompilacja jest kompilacją DEBUG - po prostu zamień na NSLog.
Grouchal
6
Implementację DLog można zobaczyć tutaj: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long
3
To mi ładnie działa. Ale aby przyspieszyć, czy istnieje sposób na usunięcie wszystkich obiektów określonego bytu za pomocą jednego polecenia? Podobnie jak w SQL, możesz zrobić coś w stylu DROP TABLE nazwa_instancji. Nie chcę usuwać całego pliku SQL, ponieważ chcę tylko usunąć wszystkie obiekty określonego obiektu, a nie innych obiektów.
ma11hew28,
8
Użyj NSDictionary * allEntities = _managedObjectModel.entitiesByName; aby uzyskać wszystkie encje w swoim modelu, a następnie można iterować po kluczach w tym NSDictionary, aby wyczyścić wszystkie encje w sklepie.
adam0101
60

Zaktualizowane rozwiązanie dla iOS 10+

Służy NSBatchDeleteRequestdo usuwania wszystkich obiektów w encji bez konieczności ładowania ich do pamięci lub iteracji przez nie.

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

Ten kod został zaktualizowany dla iOS 10 i Swift 3. Jeśli potrzebujesz obsługiwać iOS 9, zobacz to pytanie .

Źródła:

Suragch
źródło
3
Chciałbym umieścić ten cały blok wewnątrz moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect,
2
Upewnij się, że widzisz Dlaczego wpisy nie są usuwane, dopóki aplikacja nie zostanie ponownie uruchomiona lub nie wykonam mojego NSBatchDeleteRequest dwa razy? Długa historia powyższy kod NIE wystarcza, jeśli byty zostaną załadowane do pamięci
Honey,
38

Napisałem clearStoresmetodę, która przechodzi przez każdy sklep i usuwam ją zarówno z koordynatora, jak i systemu plików (pomijając błędy po bokach):

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;

Ta metoda znajduje się w coreDataHelperklasie, która zajmuje się (między innymi) tworzeniem trwałego magazynu, gdy jest on zerowy.

samvermette
źródło
„brak znanej metody klasy dla selektora„ persistentStores ””
Aviram Netanel
27

Usuwam wszystkie dane z podstawowych danych na przycisku Zdarzenie w klasie HomeViewController: Ten artykuł pomógł mi tak bardzo, że pomyślałem, że wrócę.

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

}

Zauważ, że aby wywołać self.persistentStoreCoordinator, zadeklarowałem właściwość w kontrolerze Home View. (Nie martw się o manageObjectContext, którego używam do zapisywania i ładowania).

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

Następnie w AppDelegate ApplicationDidFinishLaunching tuż poniżej, tworząc HomeViewController, mam:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;
atreat
źródło
@ayteat, czy to zadziałało dla ciebie ?. dla mnie to nie działa, proszę spojrzeć na ten stackoverflow.com/questions/14646595/…
Ranjit
1
TO ODPOWIEDŹ oprócz użycia „AppDelegate * ad = [[UIApplication sharedApplication] delegat];” i zamień ja na reklamę. i nie kopiuj ostatnich dwóch bitów kodu
Cescy
1
Dlaczego nie wywołujesz resetowania na managedObjectContext? Co zrobić, jeśli masz jakieś silne odniesienie do manageObject?
Parag Bafna
@ParagBafna Masz rację, powyższy przykładowy kod zakłada, że ​​nie ma silnych odniesień do zarządzanych obiektów. Jeśli masz, powinieneś spojrzeć na wywołanie „reset” na manageObjectContext i odesłać wszystkie posiadane obiekty zarządzane.
atreat
Hej dzięki. Czy jest też jakiś sposób to zrobić przy aktualizacji aplikacji? Mówiąc ściślej, moim wymaganiem jest to, że kiedy uruchamiam następną wersję aplikacji, kiedy użytkownik aktualizuje swoją aplikację z AppStore, podstawowe dane n plików sqlite powinny zostać usunięte i ponownie zainicjowane do stanu pustego. Wymyśliłem sposób na wykrycie pierwszego uruchomienia aplikacji za pomocą wartości Bool w NSUserDefaults i sprawdzenie tej wartości w didfinishLaunchingWithOptions delegata aplikacji, ale nie rozumiem, jak wyczyścić wszystkie te rzeczy. Ponieważ nie ma przycisku, a delegat aplikacji nie wykrywa mojego „sklepu trwałego”, aby go wyczyścić, tak jak powyżej. jakaś pomoc?
Tejas
19

MagicalRecord sprawia, że ​​jest to bardzo łatwe.

[MyCoreDataObject MR_truncateAll];
Brian King
źródło
16
to jest fajne, ale nie na temat, ponieważ określiłem rozwiązanie CoreData
Michael Grinich,
8
Active Record Fetching to podstawowe rozwiązanie danych.
casademora
7
Ale taka odpowiedź wykracza poza zakres pytania. Nie ma powodu, aby zakładać, że chce do tego celu użyć ramy addt'l.
jpswain
Twierdziłbym, że to nie odpowiada na pytanie. To dobry sposób na usunięcie wpisów z jednego podmiotu, nie wszystkich podmiotów ...! Jak wyliczyć wszystkie jednostki w modelu i wysłać MR_truncateAllje?
fatuhoku,
Wyświetl źródło MR_truncateAll - pobiera wszystkie obiekty, ale nie ich właściwości (ponieważ zamierzamy odrzucić NSMO), a następnie iteruje obiekty dla określonego obiektu i usuwa je. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t
19

iOS9 +, Swift 2

Usuń wszystkie obiekty we wszystkich obiektach

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
źródło
1
Upewnij się, że widzisz Dlaczego wpisy nie są usuwane, dopóki aplikacja nie zostanie ponownie uruchomiona lub nie wykonam mojego NSBatchDeleteRequest dwa razy? Długa historia powyższy kod NIE wystarcza, jeśli byty zostaną załadowane do pamięci
Honey,
13

[Późna odpowiedź w odpowiedzi na nagrodę z prośbą o nowe odpowiedzi]

Przeglądając wcześniejsze odpowiedzi,

  • Pobieranie i usuwanie wszystkich elementów, zgodnie z sugestią @Grouchal i innych, jest nadal skutecznym i użytecznym rozwiązaniem. Jeśli masz bardzo duże magazyny danych, może to być powolne, ale nadal działa bardzo dobrze.
  • Po prostu usunięcie magazynu danych nie jest już skuteczne, jak zauważyłeś Ty i @groundhog. Jest przestarzały, nawet jeśli nie używasz zewnętrznej pamięci binarnej, ponieważ iOS 7 korzysta z trybu WAL do dziennika SQLite. W trybie WAL mogą znajdować się (potencjalnie duże) pliki dziennika dla każdego trwałego sklepu Core Data.

Ale istnieje inne, podobne podejście do usuwania trwałego sklepu, który działa. Kluczem jest umieszczenie pliku trwałego sklepu we własnym podkatalogu, który nie zawiera niczego innego. Nie umieszczaj go tylko w katalogu dokumentów (lub gdziekolwiek), utwórz nowy podkatalog tylko dla trwałego sklepu. Zawartość tego katalogu zakończy się trwałym plikiem magazynu, plikami dziennika i zewnętrznymi plikami binarnymi. Jeśli chcesz zniszczyć cały magazyn danych, usuń ten katalog, a wszystkie znikną.

Zrobisz coś takiego podczas konfigurowania trwałego sklepu:

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

Gdy chcesz usunąć sklep,

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

To rekurencyjnie usuwa zarówno niestandardowy podkatalog, jak i wszystkie zawarte w nim pliki danych podstawowych.

Działa to tylko wtedy, gdy nie masz jeszcze trwałego sklepu w tym samym folderze, co inne ważne dane . Podobnie jak katalog dokumentów, który prawdopodobnie zawiera inne przydatne rzeczy. W takiej sytuacji możesz uzyskać ten sam efekt, szukając plików, które chcesz zachować, i usuwając wszystko inne. Coś jak:

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

Takie podejście może być podatne na błędy . Musisz być absolutnie pewien, że znasz każdy plik, który chcesz zachować, ponieważ w przeciwnym razie możesz usunąć ważne dane. Z drugiej strony możesz usunąć zewnętrzne pliki binarne, nie znając nazwy pliku / katalogu użytego do ich przechowywania.

Tom Harrington
źródło
jeśli boisz się pliku wal, po prostu wyłącz go
onmyway133
11

Oto połączone rozwiązanie do usuwania podstawowych danych.

- (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
źródło
10

Jeśli chcesz usunąć wszystkie obiekty i nie chcesz usuwać plików kopii zapasowej, możesz użyć następujących metod:

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

Uwaga: może być bardzo powolny (zależy od liczby obiektów na wykresie obiektów).

Marián Černý
źródło
jak usunąć starsze dane (powiedzmy trzy tabele, z jednej tabeli chcę wyczyścić dane) podczas aktualizacji aplikacji
Madan Mohan
6

Jeśli chcesz przejść, usuń trasę wszystkich obiektów (co jest znacznie prostsze niż zbieranie stosu danych podstawowych, ale mniej wydajne), to jest lepsza implementacja:

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

Ta implementacja wykorzystuje się NSOperationdo usunięcia głównego wątku i powiadomienia o zakończeniu. Możesz wysłać powiadomienie lub coś w obrębie bloku zakończenia, aby przywrócić status do głównego wątku.

Blake Watters
źródło
Zauważ, że twój NSManagedObjectContext musi być zainicjowany jak NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];w celu użycia tej metody, inaczej pojawi się błąd:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Czy
6

Rozwiązanie 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()
        }
    }
}

Iteruje przez wszystkie podstawowe jednostki danych i usuwa je

KVISH
źródło
4

Dzięki za post. Poszedłem za tym i zadziałało to dla mnie. Ale miałem inny problem, który nie został wymieniony w żadnej z odpowiedzi. Nie jestem więc pewien, czy to tylko ja.

W każdym razie myślałem, że opublikuję tutaj problem i sposób, w jaki go rozwiązałem.

Miałem kilka rekordów w bazie danych, chciałem wyczyścić wszystko przed zapisaniem nowych danych do bazy danych, więc zrobiłem wszystko, w tym

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

a następnie używane managedObjectContextdo uzyskiwania dostępu do bazy danych (która powinna być teraz pusta), w jakiś sposób dane nadal tam były. Po pewnym czasie rozwiązywania problemu, znalazłem, że muszę zresetować managedObjectContext, managedObject, managedObjectModeli persistentStoreCoordinator, zanim mogę użyć managedObjectContextaby uzyskać dostęp do dabase. Teraz mam czystą bazę danych do pisania.

DanielZ
źródło
Czy więc resetowanie managedObjectContext, manageObject, manageObjectModel i persistentStoreCoordinator przywraca plik zawierający bazę danych po jej usunięciu?
Daniel Brower
4

Oto nieco uproszczona wersja z mniejszą liczbą wywołań funkcji AppDelegate i ostatnim fragmentem kodu, który został pominięty w najlepiej ocenianej odpowiedzi. Pojawił się również błąd „Stały obiekt nie jest osiągalny z koordynatora tego NSManagedObjectContext”, więc po prostu musiałem go dodać.

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
źródło
4

szybkie rozwiązanie:

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
źródło
Dla szybkiego 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido
3

Jako szybkie odniesienie do zapisywania wyszukiwania w innym miejscu - odtworzenie trwałego sklepu po usunięciu można wykonać za pomocą:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
TimD
źródło
Próbowałem twojego kodu, ale xcode zgłasza wyjątek w tej linii, więc co masz do powiedzenia na ten temat.
Ranjit
3

Kilka dobrych odpowiedzi na to pytanie. Oto miło zwięzłe. Pierwsze dwa wiersze usuwają bazę danych sqlite. Następnie pętla for: usuwa wszystkie obiekty z pamięci manageObjectContext.

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
źródło
1
Nie nadużywaj delegacji w tym celu: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner
1
Zgadzam się z @MichaelDorner. Dodanie czegoś do AppDelegate może wpłynąć na wydajność i nadmuchać rozmiar twojego pliku binarnego za pomocą połączonej pajęczyny zależności, w której AppDelegate nagle musi zostać włączony do każdej klasy. Jeśli okaże się, że to się pojawia, utwórz osobny kontroler specyficzny dla tego celu. AppDelegate powinien pozostać do podstawowej inicjalizacji i obsługi zmian stanu w aplikacji, nie więcej.
jcpennypincher
2

możesz także znaleźć wszystkie nazwy jednostek i usunąć je według nazwy. Jest to dłuższa wersja, ale działa dobrze, dzięki czemu nie musisz pracować ze sklepem z trwałością

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

w przypadku „Any_Entity_Name” wystarczy podać dowolną nazwę swojej jednostki, musimy tylko dowiedzieć się, jaki jest jej opis. ValueForKey @ „name” zwróci wszystkie nazwy encji. Wreszcie, nie zapomnij zapisać.

Chris Lin
źródło
2

Przyjęta odpowiedź jest poprawna, a usunięcie adresu URL przez NSFileManager jest prawidłowe, ale jak stwierdzono w edycji iOS 5+, trwały sklep nie jest reprezentowany tylko przez jeden plik. W przypadku sklepu SQLite jest to * .sqlite, * .sqlite-shm i * .sqlite-wal ... na szczęście od iOS 7+ możemy użyć metody

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: opcje: błąd:]

aby zająć się usunięciem, więc kod powinien wyglądać mniej więcej tak:

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
źródło
2
Musisz przekazać dyktowanie opcji, w szczególności nazwę sklepu, np .: @ {NSPersistentStoreUbiquitousContentNameKey: @ „MyData”};
tomi44g
2

Oto wersja, która usuwa każdy rekord w każdej tabeli, którą masz.

Szybki 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
źródło
2

Swift 4/5, iOS 9+

Przebudowa całego CoreDatapliku SQLite sprawi, że wszystkie dane zostaną usunięte, dlatego wszystkie jednostki zostaną usunięte. Po prostu zadzwoń 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
źródło
dla każdego, kto tego używa, pamiętaj, że spowoduje to awarię „pierwszego razu”, gdy nie będzie tam pliku sql (w odpowiedzi użyłem „strażnika”)
Fattie
1

Działa ze wszystkimi wersjami. Przekaż nazwę encji i iteruj, aby usunąć wszystkie wpisy i zapisać kontekst.

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
źródło
1

Inną metodą (oprócz żądania usunięcia partii), której często używam (w zależności od wymagań aplikacji), jest zresetowanie trwałego sklepu. Implementacja wygląda następująco dla iOS 10+ i Swift (zakładając, że masz klasę 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)
        }
    }

}

Jedną z zalet tej metody jest to, że jest ona prostsza, szczególnie gdy masz wiele rekordów danych dla wielu jednostek w swoich podstawowych danych. W takim przypadku żądanie usunięcia partii będzie wymagało dużej ilości pamięci.

Oluwatobi Omotayo
źródło
1

Rozwiązanie 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
źródło
0

Usunąć plik sklepu trwałego i skonfigurować nowego koordynatora sklepu trwałego?

myśliwy
źródło
6
Wykonanie czyszczenia nie usunie plików trwałego sklepu, na szczęście. Byłby to przepis na katastrofę, jeśli byłby prawdziwy.
Hunter,
0

Usuń sqlite z plikuURLPath, a następnie buduj.

Jai
źródło
Miałem na myśli, gdy aplikacja jest zainstalowana.
Michael Grinich,
0

Zakładając, że używasz MagicalRecordi masz domyślny magazyn trwałości:

Nie podoba mi się wszystkie rozwiązania, które zakładają istnienie określonych plików i / lub wymagają wprowadzenia nazw lub klas jednostek. Jest to szybki (2), bezpieczny sposób na usunięcie wszystkich danych ze wszystkich encji. Po usunięciu odtworzy również nowy stos (tak naprawdę nie jestem pewien, jak niezbędna jest ta część).

Jest godo dla sytuacji w stylu „wylogowania”, gdy chcesz usunąć wszystko, ale masz działający sklep i moc, aby uzyskać nowe dane (po zalogowaniu się użytkownika ...)

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
źródło
0

Użyj tego

+(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
źródło
0

Wziąłem kod Grouchala i aby go przyspieszyć, użyłem wyliczenia w trybie współbieżnym ( NSEnumerationConcurrent), stał się on nieco szybszy w porównaniu do pętli for (w mojej aplikacji dodałem tę funkcję dla testerów, aby mogli oni wyczyścić dane i wykonać przypadki testowe zamiast usuwać i Zainstaluj aplikację)

- (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
źródło
0

tutaj moja wersja swift3 do usuwania wszystkich rekordów. „Użytkownicy” to nazwa podmiotu

@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
źródło