Видалити / скинути всі записи в основних даних?


235

Чи знаєте ви яким-небудь способом видалити всі записи, що зберігаються в основних даних? Моя схема повинна залишатися такою ж; Я просто хочу скинути його на порожнє.


Редагувати

Я хочу зробити це програмно, щоб користувач міг по суті натиснути resetкнопку.


6
Багато відповідей нижче датовані. Використовуйте NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Відповіді:


198

Ви все ще можете видалити файл програмно, використовуючи метод NSFileManager: removeItemAtPath ::.

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

Потім просто додайте стійкий магазин назад, щоб переконатися, що він відтворений належним чином.

Програмний спосіб ітерації через кожну сутність є і повільнішим, і схильним до помилок. Використання цього способу полягає в тому, якщо ви хочете видалити деякі об'єкти, а не інші. Однак вам все-таки потрібно переконатися, що ви зберігаєте референтну цілісність або не зможете зберегти свої зміни.

Просто вийняти магазин і відтворити його - це і швидко, і безпечно, і це, безумовно, можна зробити програмно під час виконання.

Оновлення для iOS5 +

При впровадженні зовнішнього бінарного сховища (дозволяєExternalBinaryDataStorage або зберігати у зовнішньому файлі запису) в iOS 5 та OS X 10.7, просто видалення файлів, вказаних на storeURL, недостатньо. Ви залишите зовнішні файли запису позаду. Оскільки схема називання цих зовнішніх файлів записів не є загальнодоступною, я ще не маю універсального рішення. - an0 8 травня 12 о 23:00


1
Це, мабуть, найкраще рішення для надійності. Якби я хотів , щоб видалити деякі , але не всі дані, я хотів би використовувати це: stackoverflow.com/questions/1077810 / ...
Майкл Grinich

12
Я знаю, як правильно отримати координатор магазину. Однак я не знаю, як отримати стійкий магазин. Тож чи можете ви надати належний приклад замість просто: NSPersistentStore * store = ...;
Паскаль Кляйн

11
[[NSFileManager defaultManager] removeItemAtURL: errorURL error: & error] - краще.
an0

3
@Pascal Якщо ви можете отримати координатора магазину, ви маєте доступ до всіх своїх постійних магазинів через властивість persistentStores.
Міхай Даміан

2
Приклад коду, включаючи, як відтворити новий порожній магазин тут: stackoverflow.com/a/8467628
Джошуа С. Лернер

140

Ви можете видалити файл SQLite, але я вирішу це зробити, очищаючи таблиці окремо за допомогою функцій:

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

}

Причиною, що я вирішив це робити за таблицею, є те, що під час виконання програми я підтверджую, що видалення вмісту таблиці є розумним, і немає даних, які я б краще зберігав.

Зробити це буде набагато повільніше, ніж просто видалити файл, і я перейду на видалення файлу, якщо мені цей метод зайняє занадто багато часу.


Прекрасне рішення. Дякую. Що таке DLog ()?
Майкл Гриніч

Так, вибачте, що це особлива функція, яку я використовую, що виконує NSLog лише тоді, коли збірка - це DEBUG-збірка - просто замініть на NSLog.
Grouchal

6
Ви можете побачити реалізацію DLog тут: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long

3
Це прекрасно працює для мене. Але щоб зробити це швидше, чи існує спосіб видалити всі об’єкти певної сутності за допомогою однієї команди? Як і в SQL, ви можете зробити щось на кшталт DROP TABLE name_name. Я не хочу видаляти весь файл SQL, оскільки я хочу лише видалити всі об'єкти певної сутності, а не інші об'єкти.
ma11hew28

8
Використовуйте NSDictionary * allEntities = _managedObjectModel.entitiesByName; щоб отримати всі об'єкти у вашій моделі, а потім ви можете перебирати клавіші цього NSDictionary, щоб очистити всі об’єкти в магазині.
adam0101

60

Оновлене рішення для iOS 10+

Використовуйте NSBatchDeleteRequestдля видалення всіх об'єктів в об'єкті, не завантажуючи їх у пам'ять або повторюючи їх.

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

Цей код було оновлено для iOS 10 та Swift 3. Якщо вам потрібно підтримати iOS 9, перегляньте це питання .

Джерела:


3
Я б на місці , що весь блок всередині moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect

2
Переконайтесь, що ви бачите, чому записи не видаляються, доки програма не буде перезапущена або я не виконаю свій NSBatchDeleteRequest двічі? Довгої історії вищевказаного коду НЕ вистачить, якщо сутності завантажуються в пам'ять
Honey

38

Я написав clearStoresметод, який проходить через кожен магазин і видаляє його як з координатора, так і з файлової системи (обробка помилок зліва):

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;

Цей метод знаходиться всередині coreDataHelperкласу, який опікується (серед іншого) створенням persistentStore, коли він нульовий.


"не відомий метод класу для селектора" persistentStores ""
Авірам Нетанел

27

Я видаляю всі дані з основних даних на кнопці Подія класу HomeViewController: Ця стаття мені так допомогла, я зрозумів, що буду внести свій внесок.

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

}

Зауважте, що для виклику self.persistentStoreCoordinator я оголосив властивість у контролері домашнього перегляду. (Не хвилюйтеся про керованийOObjectContext, який я використовую для збереження та завантаження.)

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

Потім в AppDelegate ApplicationDidFinishLaunching, створеному нижче, створено HomeViewController:

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

@ayteat, це працювало для тебе? для мене це не працює, перегляньте цей stackoverflow.com/questions/14646595/…
Ranjit

1
ЦЕ ВІДПОВІДЬ, за винятком використання "AppDelegate * ad = [[UIApplication sharedApplication] delegate];" і замінити себе на рекламу. і не копіюйте останні два біти коду
Cescy

1
Чому ви не викликаєте скидання в ManagedObjectContext? Що робити, якщо у вас є чітке посилання на ManagedObject?
Параг Бафна

@ParagBafna Ви праві, наведений вище зразок коду передбачає, що немає чітких посилань на керовані об'єкти. Якщо у вас є деякі, вам слід поглянути на виклик "скинути" на ManagedObjectContext і видалити посилання на всі керовані вами об'єкти.
atreat

Гей, спасибі Крім того, чи можливо це зробити при оновленні додатків? Якщо бути точним, моя вимога полягає в тому, коли я перекидаю наступну версію програми, коли час, коли користувач оновлює свою програму з appStore, основні дані n sqlite файли повинні бути видалені та повторно ініціалізовані до порожнього. Я з'ясував спосіб виявити подію першого запуску програми за допомогою значення Bool у NSUserDefaults і перевірити це значення в didfinishLaunchingWithOptions делегата додатка, але не зрозумів, як очистити всі ці речі. Оскільки немає кнопки, а делегат програми не виявляє мого "persistentStore", щоб очистити його, як ви робили вище. будь-яка допомога?
Теяс

19

MagicalRecord робить це дуже просто.

[MyCoreDataObject MR_truncateAll];

16
це класно, але поза темою, оскільки я вказав рішення CoreData
Майкл Грініч

8
Активне отримання записів - це основне рішення даних.
casademora

7
Але така відповідь виходить за межі питання. Немає підстав вважати, що він хоче використовувати для цього додаткові рамки.
jpswain

Я б стверджував, що це не відповідає на питання. Це хороший спосіб видалити записи з однієї сутності, а не всіх організацій ...! Як ви перераховуєте всі об'єкти в моделі та надсилаєте MR_truncateAllїх?
фатухоку

Перегляньте джерело для MR_truncateAll - воно отримує всі об'єкти, але не їх властивості (як ми маємо намір відкинути NSMO), потім воно перебирає об'єкти для вказаної сутності та видаляє їх. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
1in9ui5t

19

iOS9 +, Swift 2

Видаліть усі об'єкти в усіх об'єктах

func clearCoreDataStore() {
    let entities = managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.executeRequest(deleteReqest)
        } catch {
            print(error)
        }
    }
}

1
Переконайтесь, що ви бачите, чому записи не видаляються, доки програма не буде перезапущена або я не виконаю свій NSBatchDeleteRequest двічі? Довгої історії вищевказаного коду НЕ вистачить, якщо сутності завантажуються в пам'ять
Honey

13

[Пізня відповідь у відповідь на щедрості з проханням отримати новіші відповіді]

Переглядаючи попередні відповіді,

  • Вилучення та видалення всіх елементів, як це запропонувало @Grouchal та інші, все ще є ефективним і корисним рішенням. Якщо у вас дуже великі сховища даних, то це може бути повільним, але воно все ще працює дуже добре.
  • Просто вилучення сховища даних, як зазначаєте ви @ @groundhog, вже не ефективно. Це застаріло, навіть якщо ви не використовуєте зовнішнє бінарне сховище, оскільки iOS 7 використовує режим WAL для перегляду SQLite. У режимі WAL можливі (потенційно великі) файли журналів, які сидять навколо будь-якого постійного магазину Core Data.

Але існує інший, подібний підхід до вилучення постійного магазину, який працює. Ключ полягає в тому, щоб помістити свій постійний файл зберігання у власний підкаталог, який не містить нічого іншого. Не просто вставляти його в каталог документів (або де завгодно), створюйте новий підкаталог тільки для постійного магазину. Вміст цього каталогу в кінцевому підсумку буде постійним файлом зберігання, файлами журналів та зовнішніми бінарними файлами. Якщо ви хочете запустити все сховище даних, видаліть цей каталог, і всі вони зникнуть.

Ви зробите щось подібне, налаштовуючи свій постійний магазин:

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

Тоді, коли ви хотіли прибрати магазин,

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

Це рекурсивно видаляє як користувацький підкаталог, так і всі файли основних даних у ньому.

Це працює лише в тому випадку, якщо у вас ще немає постійного зберігання в тій же папці, що й інші важливі дані . Як і каталог документів, в якому, ймовірно, є інші корисні речі. Якщо це ваша ситуація, ви можете отримати той же ефект, дивлячись на файли , які ви дійсно хочете зберегти і видалити все інше. Щось на зразок:

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

Цей підхід може бути схильним до помилок . Ви повинні бути абсолютно впевнені, що знаєте кожен файл, який хочете зберегти, оскільки в іншому випадку ви можете видалити важливі дані. З іншого боку, ви можете видалити зовнішні бінарні файли, фактично не знаючи імені файлу / каталогу, який використовується для їх зберігання.


якщо ви боїтесь файлу
wal

11

Ось комбіноване рішення для очищення основних даних.

- (void)deleteAllObjectsInCoreData
{
    NSArray *allEntities = self.managedObjectModel.entities;
    for (NSEntityDescription *entityDescription in allEntities)
    {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];

        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;

        NSError *error;
        NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (error) {
                NSLog(@"Error requesting items from Core Data: %@", [error localizedDescription]);
            }

        for (NSManagedObject *managedObject in items) {
            [self.managedObjectContext deleteObject:managedObject];
        }

        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }  
}

10

Якщо ви хочете видалити всі об'єкти та не хочете видалити резервні файли, ви можете скористатися такими методами:

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

Будьте уважні, що це може бути дуже повільним (залежить від того, скільки об’єктів у вашому графіку об'єктів).


як видалити старіші дані (скажімо, три таблиці, з однієї таблиці я хочу очистити дані), коли оновлення додатків
Мадан Мохан

6

Якщо ви хочете пройти шлях видалення всіх об'єктів (що набагато простіше, ніж зірвати стек основних даних, але менш ефективний), це краща реалізація:

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

Ця реалізація використовує NSOperationдля вилучення основного потоку та сповіщення про завершення. Ви можете надіслати сповіщення або щось у блоці завершення, щоб передати стан назад у основний потік.


Зауважте, що ваш NSManagedObjectContext повинен бути ініціалізований як NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];для використання цього методу, інакше ви отримаєте помилку:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Буде

6

Рішення для 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()
        }
    }
}

Взаємодіє через усі основні суб'єкти даних та очищає їх


4

Дякую за пост. Я дотримувався цього, і це працювало на мене. Але у мене було ще одне питання, яке не згадувалося в жодній із відповідей. Тож я не впевнений, чи це був лише я.

У всякому разі, я думав, що опублікую тут проблему та мій шлях, який її вирішив.

У мене було кілька записів у базі даних, я хотів очистити все чисте, перш ніж писати нові дані в db, тому я робив усе, включаючи

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

а потім використовувався managedObjectContextдля доступу до бази даних (мабуть, до цього часу він був порожнім), якимось чином дані все ще були. Через деякий час усунення неполадок, я виявив , що мені потрібно скинути managedObjectContext, managedObject, managedObjectModelі persistentStoreCoordinator, перш ніж я використовувати managedObjectContextдля доступу до dabase. Тепер я маю чисту базу даних для запису.


Отже, скидання ManagedObjectContext, ManagedObject, ManagedObjectModel та persistentStoreCoordinator повертає файл, що містить базу даних, після її видалення?
Даніел Броуер

4

Ось дещо спрощена версія з меншою кількістю дзвінків у AppDelegate self та останній біт коду, який залишився поза найкращою оцінкою. Також я отримував помилку "Постійний магазин об'єкта недоступний від цього координатора NSManagedObjectContext", тому просто потрібно було додати його назад.

NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
NSPersistentStore *store = [[storeCoordinator persistentStores] lastObject];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"dataModel"];
NSError *error;

[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

if (storeCoordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}

4

швидке рішення:

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

Для швидкої 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Саорікідо

3

Як швидке посилання на збереження пошуку в іншому місці - відтворення стійкого магазину після його видалення можна зробити за допомогою:

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

Я спробував ваш код, але xcode кидає виняток у цьому рядку, так що ви маєте сказати про це.
Ранджіт

3

Кілька хороших відповідей на це питання. Ось приємний стислий. Перші два рядки видаляють базу даних sqlite. Тоді цикл for: видаляє будь-які об'єкти в пам'яті ManagedObjectContext.

NSURL *storeURL = [[(FXYAppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppName.sqlite"];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
for (NSManagedObject *ct in [self.managedObjectContext registeredObjects]) {
    [self.managedObjectContext deleteObject:ct];
}

1
Не зловживайте делегацією з цією метою: hollance.com/2012/02/dont-abuse-the-app-delegate
Майкл Дорнер

1
Я згоден з @MichaelDorner. Додавання багато чого в AppDelegate може вплинути на продуктивність та збільшити розмір вашого двійкового файлу за допомогою взаємопов’язаної павутини залежностей, де AppDelegate раптом потрібно включити до кожного класу. Якщо ви виявите це обрізання, створіть окремий контролер, специфічний для цієї мети. AppDelegate повинен залишатися для основної ініціалізації та обробки змін стану додатків, не набагато більше.
jcpennypincher

2

ви також можете знайти всі назви сутностей та видалити їх за назвою. Його довша версія, але працює добре, тому вам не доведеться працювати з магазином наполегливості

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

для "Any_Entity_Name" просто вкажіть будь-яке ім'я вашої організації, нам потрібно лише з'ясувати опис юридичної особи, до якої належать ваші особи. ValueForKey @ "name" поверне всі імена сутності. Нарешті, не забудьте зберегти.


2

Прийнята відповідь є правильною, видалення URL-адреси NSFileManager є правильним, але, як зазначено в редакції iOS 5+, стійкий магазин не представлений лише одним файлом. Для магазину SQLite це * .sqlite, * .sqlite-shm та * .sqlite-wal ... на щастя, оскільки для iOS 7+ ми можемо використовувати метод

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: options: error:]

щоб подбати про видалення, тому код повинен бути приблизно таким:

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSString *storeName = ...;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL.path options:@{NSPersistentStoreUbiquitousContentNameKey: storeName} error:&error];

2
Вам потрібно передати параметр dict, зокрема назву магазину, наприклад: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g

2

Ось версія, яка видаляє кожен запис у кожній вашій таблиці.

Швидкий 4

static func resetDatabase() {
    do {
        try dataStore.persistentStoreCoordinator.managedObjectModel.entities.forEach { (entity) in
            if let name = entity.name {
                let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                let request = NSBatchDeleteRequest(fetchRequest: fetch)
                try mainContext.execute(request)
            }
        }

        try mainContext.save()
    } catch {
        print("error resenting the database: \(error.localizedDescription)")
    }
}

2

Swift 4/5, iOS 9+

Перебудова всього CoreDataфайлу SQLite гарантує, що всі дані будуть видалені, тому всі об'єкти видаляються. Просто зателефонуйте 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()
    }
}

для тих, хто використовує це, зауважте, що він просто вийде з ладу в "перший раз", коли там немає файлу sql (я просто використав "охоронець" у своїй відповіді)
Fattie

1

Працює з усіма версіями. Введіть ім'я сутності та повторіть, щоб видалити всі записи та зберегти контекст.

func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
    var context = NSManagedObjectContext()
    if #available(iOS 10.0, *) {
        context = self.persistentContainer.viewContext
    } else {
        context = self.managedObjectContext
    }

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
    fetchRequest.entity = NSEntityDescription.entity(forEntityName: entityToFetch, in: context)
    fetchRequest.includesPropertyValues = false
    do {
        let results = try context.fetch(fetchRequest) as! [NSManagedObject]
        for result in results {
            context.delete(result)
        }
        try context.save()
        completion(true)
    } catch {
        completion(false)
        print("fetch error -\(error.localizedDescription)")
    }
}

1

Ще один метод (окрім запиту на видалення партії), який я часто використовую (на основі вимог програми), - це скидання стійкого магазину. Реалізація виглядає приблизно так для iOS 10+ та Swift (якщо у вас є клас 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)
        }
    }

}

Однією з переваг цього методу є те, що він є більш простим, особливо коли у ваших основних даних є багато записів даних для багатьох об'єктів. У такому випадку запит на видалення буде інтенсивним для пам'яті.


1

Швидкий 5.1 Рішення

public static func reset() {
    let coordinator = _persistentContainer.persistentStoreCoordinator
    for store in coordinator.persistentStores where store.url != nil {
        try? coordinator.remove(store)
        try? FileManager.default.removeItem(atPath: store.url!.path)
    }
}

0

Видалити постійний файл магазину та встановити нового постійного координатора магазину?


6
Чисте очищення не призведе до видалення стійких файлів магазину, на щастя. Це був би рецепт катастрофи, якщо це правда.
Мисливець


0

Якщо припустити, що ви використовуєте MagicalRecordі зберігаєте постійну сховище:

Мені не подобаються всі рішення, які передбачають існування певних файлів та / або вимагають введення імен чи класів сутностей. Це Swift (2), безпечний спосіб видалення всіх даних з усіх об'єктів. Після видалення він також відтворить свіжий стек (я фактично не впевнений у тому, наскільки потрібна ця частина).

Це Godo для ситуацій стилю "вихід", коли ви хочете видалити все, але у вас є робочий магазин і moc для отримання нових даних (як тільки користувач увійде в систему ...)

extension NSManagedObject {

    class func dropAllData() {

        MagicalRecord.saveWithBlock({ context in

            for name in NSManagedObjectModel.MR_defaultManagedObjectModel().entitiesByName.keys {
                do { try self.deleteAll(name, context: context) }
                catch { print("⚠️ ✏️ Error when deleting \(name): \(error)") }
            }

            }) { done, err in
                MagicalRecord.cleanUp()
                MagicalRecord.setupCoreDataStackWithStoreNamed("myStoreName")
        }
    }

    private class func deleteAll(name: String, context ctx: NSManagedObjectContext) throws {
        let all = NSFetchRequest(entityName: name)
        all.includesPropertyValues = false

        let allObjs = try ctx.executeFetchRequest(all)
        for obj in allObjs {
            obj.MR_deleteEntityInContext(ctx)
        }

    }
}

0

Використовуй це

+(NSArray *)fetchDataFromEntity:(NSString *)entityName context:(NSManagedObjectContext *)context
{
    NSFetchRequest * fetchRequest =[[NSFetchRequest alloc] init];
    NSEntityDescription * CategoriesEntity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
    [fetchRequest setEntity:CategoriesEntity];

    NSError * error;
    NSInteger count = [context countForFetchRequest:fetchRequest error:&error];

    if (count && count>0) {

        NSArray * fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects && fetchedObjects.count>0) {

            return fetchedObjects;
        }else
            return nil;

    }
    else
        return nil;
}
+ (void)deleteObjectsOfArray:(NSMutableArray*)ary context:(NSManagedObjectContext *)context {
    for (NSManagedObject * obj in ary) {
        [context deleteObject:obj];
    }
    NSError *saveError = nil;
    [context save:&saveError];
}
+ (void)deleteEntity:(NSString *)entityName context:(NSManagedObjectContext *)context {
    NSArray *listArray = [self fetchDataFromEntity:entityName context:context];
    [self deleteObjectsOfArray:[NSMutableArray arrayWithArray:listArray] context:context];
}

0

Я взяв код Grouchal і щоб пришвидшити його, я використав перерахування з паралельним режимом ( NSEnumerationConcurrent), він став трохи швидшим порівняно з для циклу (у своєму додатку я додав цю функцію для Testers, щоб вони могли очищати дані та робити тестові шкали, а не видаляти і встановити додаток)

- (void)resetObjects
{
    [self deleteAllObjectsInEntity:@"Entity1"];
    [self deleteAllObjectsInEntity:@"Entity2"];
    [self deleteAllObjectsInEntity:@"Entity3"];
    [self deleteAllObjectsInEntity:@"Entity4"];
}

-(void) deleteAllObjectsInEntity:(NSString*) entityName
{
    MainDataContext *coreDataContext = [MainDataContext sharedInstance];
    NSManagedObjectContext *currentContext = coreDataContext.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:currentContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [currentContext executeFetchRequest:fetchRequest error:&error];

    [items enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSManagedObject * obj, NSUInteger idx, BOOL *stop) {
        [currentContext deleteObject:obj];
    }];


    if (![currentContext save:&error]) {
        NSLog(@"Error deleting %@ - error:%@",entityName,error);
    }
}

0

ось моя версія swift3 для видалення всіх записів. "Користувачі" - це назва організації

@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
    }   
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.