Удалить / Сбросить все записи в Базовых данных?

235

Знаете ли вы какой-либо способ удалить все записи, хранящиеся в Core Data? Моя схема должна остаться прежней; Я просто хочу сбросить его до пустого.


редактировать

Я хочу сделать это программно, чтобы пользователь мог по существу нажать resetкнопку.

Михаил Гринич
источник
6
Многие из ответов ниже датированы. Использование NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Ответы:

198

Вы все еще можете удалить файл программно, используя NSFileManager: removeItemAtPath :: method.

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

Затем просто добавьте постоянное хранилище обратно, чтобы убедиться, что оно воссоздано правильно.

Программный способ перебора каждой сущности медленнее и подвержен ошибкам. Это можно сделать, если вы хотите удалить некоторые объекты, а не другие. Однако вы все равно должны убедиться, что сохраняете ссылочную целостность, иначе вы не сможете сохранить свои изменения.

Простое удаление и воссоздание хранилища является быстрым и безопасным, и, безусловно, может быть сделано программно во время выполнения.

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

С введением внешнего двоичного хранилища (allowExternalBinaryDataStorage или Store in External Record File) в iOS 5 и OS X 10.7 простого удаления файлов, указанных в storeURL, стало недостаточно. Вы оставите внешние файлы записи позади. Поскольку схема именования этих внешних файлов записи не является общедоступной, у меня пока нет универсального решения. - до 8 мая '12 в 23:00

сурок лесной американский
источник
1
Это, наверное, лучшее решение для надежности. Если бы я хотел удалить некоторые, но не все данные, я бы использовал это: stackoverflow.com/questions/1077810/…
Михаил Гринич
12
Я знаю, как правильно получить storeCoordinator. Однако я не знаю, как получить persistentStore. Поэтому не могли бы вы привести правильный пример вместо простого: NSPersistentStore * store = ...;
Паскаль Кляйн
11
[[NSFileManager defaultManager] removeItemAtURL: ошибка storeURL: & 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);
    }

}

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

Делать это будет намного медленнее, чем просто удалить файл, и я перейду на удаление файла, если этот метод займет слишком много времени.

Grouchal
источник
Отличное решение. Спасибо. Что такое DLog ()?
Михаил Гринич
Ах да - извините, это специальная функция, которую я использую, которая делает NSLog только тогда, когда сборка является сборкой DEBUG - просто замените на NSLog.
Grouchal
6
Вы можете увидеть реализацию DLog здесь: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long
3
Это хорошо работает для меня. Но чтобы сделать это быстрее, есть ли способ удалить все объекты определенного объекта с помощью одной команды? Как и в SQL, вы можете сделать что-то вроде DROP TABLE entity_name. Я не хочу удалять весь файл SQL, потому что я хочу удалить только все объекты определенного объекта, а не других объектов.
ma11hew28
8
Use 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, посмотрите этот вопрос .

Источники:

Suragch
источник
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, когда он равен nil.

samvermette
источник
«неизвестный метод класса для селектора« persistentStores »»
Aviram Netanel
27

Я удаляю все данные из основных данных кнопки Event в классе 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 я объявил свойство в Home View Controller. (Не беспокойтесь по поводу управляемогоObjectContext, который я использую для сохранения и загрузки.)

@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;
atreat
источник
@ayteat, это сработало для тебя? для меня это не работает, пожалуйста, посмотрите на этот stackoverflow.com/questions/14646595/…
Ranjit
1
ЭТО ОТВЕТ, кроме использования "AppDelegate * ad = [[UIApplication sharedApplication] делегат];" и замени себя на рекламу. и не копируйте последние два бита кода
Сесси
1
Почему вы не вызываете метод reset для managedObjectContext? Что, если у вас есть сильная ссылка на managedObject?
Параг Бафна
@ParagBafna Вы правы, приведенный выше пример кода предполагает отсутствие строгих ссылок на управляемые объекты. Если у вас есть, вы должны посмотреть на вызов «reset» в managedObjectContext и отменить ссылку на любые ваши управляемые объекты.
atreat
Эй, спасибо. Кроме того, есть ли способ сделать это при обновлении приложения? Если быть точным, то мое требование заключается в том, чтобы при переходе на следующую версию приложения, когда пользователь обновляет свое приложение из appStore, основные данные и файлы sqlite должны быть удалены и повторно инициализированы до пустого значения. Я нашел способ обнаружить событие первого запуска приложения, используя значение Bool в NSUserDefaults и проверив это значение в didfinishLaunchingWithOptions делегата приложения, но не понял, как очистить все эти вещи. Так как кнопки нет, и приложение app не обнаруживает мой «persistentStore», чтобы очистить его, как вы делали выше. любая помощь?
Tejas
19

MagicalRecord делает это очень легко.

[MyCoreDataObject MR_truncateAll];
Брайан Кинг
источник
16
это круто, но не по теме, так как я определил решение CoreData
Михаил Гринич
8
Active Record Fetching является основным решением для обработки данных.
Касадемора
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, просто отключите его
onmyway133
11

Вот комбинированное решение для очистки Core Data.

- (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
источник
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()
        }
    }
}

Перебирает все основные объекты данных и очищает их

KVISH
источник
4

Спасибо за пост. Я следовал за этим, и это работало на меня. Но у меня была другая проблема, которая не упоминалась ни в одном из ответов. Так что я не уверен, что это был только я.

Во всяком случае, думал, что я опубликую здесь проблему и мой путь, который решил ее.

У меня было несколько записей в базе данных, я хотел очистить все, прежде чем записывать новые данные в БД, поэтому я сделал все, включая

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

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

DanielZ
источник
Таким образом, сброс параметров managedObjectContext, managedObject, managedObjectModel и persistentStoreCoordinator возвращает файл, содержащий базу данных, после ее удаления?
Даниэль Брауэр
4

Вот несколько упрощенная версия с меньшим количеством обращений к самому AppDelegate и последним кусочком кода, который остался за пределами рейтинга. Также я получаю сообщение об ошибке «Постоянное хранилище объекта недоступно из этого координатора 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")!
Saorikido
3

В качестве краткого справочника для сохранения поиска в другом месте - воссоздание постоянного хранилища после удаления может быть выполнено с помощью:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
TimD
источник
Я попробовал ваш код, но 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+ edit, постоянное хранилище не представлено только одним файлом. Для хранилища SQLite это * .sqlite, * .sqlite-shm и * .sqlite-wal ... к счастью, начиная с iOS 7+ мы можем использовать метод

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: параметры: ошибка:]

позаботиться об удалении, поэтому код должен быть примерно таким:

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
источник
2
Вам необходимо передать параметр dict, в частности имя магазина, например: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
Tomi44g
2

Вот версия, которая удаляет каждую запись в каждой вашей таблице.

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
источник
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 (я просто использовал «охранник» в своем ответе)
Толстяк
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

Решение 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)
    }
}
Чарльтон Проватас
источник
0

Удалить файл постоянного хранилища и настроить новый координатор постоянного хранилища?

охотник
источник
6
К счастью, очистка не удалит файлы из постоянного хранилища. Если бы это было правдой, это было бы рецептом катастрофы.
Охотник
0

Удалите sqlite из вашего файла ULPath, а затем соберите.

Jai
источник
Я имел в виду, когда приложение установлено.
Михаил Гринич
0

Предполагая, что вы используете MagicalRecordи сохраняете хранилище по умолчанию:

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

Это идеальный вариант для ситуаций, связанных с выходом из системы, когда вы хотите удалить все, но у вас есть работающее хранилище и 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), он стал немного быстрее по сравнению с циклом for (в моем приложении я добавил эту функцию для тестировщиков, чтобы они могли очищать данные и выполнять тестовые случаи, а не удалять и установить приложение)

- (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
источник
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
    }   
}
Курсат Туркай
источник