Удалить / сбросить все записи в основных данных?
знаете ли вы, как удалить все записи, хранящиеся в основных данных? Моя схема должна оставаться прежней; я просто хочу сбросить ее на пустую.
Edit
Я ищу, чтобы сделать это программно, так что пользователь может существенно ударить .
29 ответов:
вы все еще можете удалить файл программно, используя метод 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+
С введением внешнего двоичного хранилища (allowsExternalBinaryDataStorage или хранить во внешнем файле записи) в iOS 5 и OS X 10.7, просто удаление файлов, указанных storeURLs не достаточно. Вы оставите внешние файлы записей позади. Так как схема именования из этих внешних файлов записей не является общедоступным, у меня пока нет универсального решения. – an0 8 Май '12 в 23:00
вы можете удалить файл sqllite - но я решил сделать это, очистив таблицы по отдельности с помощью функций:
- (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); } }
причина, по которой я решил сделать это таблица за таблицей, заключается в том, что она заставляет меня подтвердить, как я делаю Программирование, что удаление содержимого таблицы разумно и нет данных, которые я бы предпочел сохранить.
делать это будет намного медленнее, чем просто удалить файл, и я изменюсь на удаление файла, если я этот метод тоже возьму длинный.
Обновлено решение для iOS 9+
использовать
NSBatchDeleteRequest
удалить все объекты, в сущности без необходимости загружать их в память или перебирать его.// create the delete request for the specified entity let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "MyEntity") let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) // get reference to the persistent container let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer // perform the delete do { try persistentContainer.viewContext.execute(deleteRequest) } catch let error as NSError { print(error) }
этот код был обновлен для iOS 10 и Swift 3. Если вам нужна поддержка iOS 9 см. этот вопрос.
источники:
- основные данные: Самый быстрый способ удалить все экземпляры сущности (включает в себя Objective-C code)
- что нового в основных данных (WWDC 2015 video)
- что нового в основных данных (WWDC 2016 видео)
- как использовать основные данные в iOS 10
- что нового в Core Data Swift 3.0
Я написал
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, когда он равен нулю.
Я удаляю все данные из основных данных о событии кнопки в классе 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 } }
обратите внимание, что для того, чтобы позвонить самостоятельно.persistentStoreCoordinator я объявил свойство в контроллере домашнего вида. (Не беспокойтесь о managedObjectContext, который я использую для сохранения и загрузки.)
@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;
MagicalRecord делает это очень легко.
[MyCoreDataObject MR_truncateAll];
[поздний ответ в ответ на щедрость с просьбой о новых ответах]
просматривая предыдущие ответы,
- извлечение и удаление всех элементов, как предложено @Grouchal и другими, по-прежнему является эффективным и полезным решением. Если у вас очень большие хранилища данных, то это может быть медленным, но он по-прежнему работает очень хорошо.
- простое удаление хранилища данных, как вы и @groundhog Примечание, больше не эффективно. Это устарело даже если вы не используете внешнее двоичное хранилище потому что iOS 7 использует режим WAL для ведения журнала SQLite. В режиме WAL могут быть (потенциально большие) файлы журналов, расположенные вокруг для любого постоянного хранилища основных данных.
но есть другой, аналогичный подход к удалению постоянного хранилища, которое действительно работает. Ключ должен поместить ваш постоянный файл хранилища в его собственный подкаталог, который не содержит ничего другого. Не просто вставьте его в каталог документов (или где бы то ни было), создайте новый подкаталог только для постоянного хранилища. Содержимое этого каталога будет представлять собой постоянный файл хранилища, файлы журнала и внешние двоичные файлы. Если вы хотите уничтожить все хранилище данных, удалите этот каталог, и все они исчезнут.
вы бы сделали что-то подобное при настройке вашего постоянного магазина:
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. }
этот подход может быть подвержен ошибкам. Вы должны быть абсолютно уверены, что вы знаете каждый файл, который вы хотите сохранить, потому что в противном случае вы можете удалить важные данные. С другой стороны, вы можете удалить внешние двоичные файлы, фактически не зная имя файла/каталога, используемого для их хранения.
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) } } }
Если вы хотите удалить все объекты и не хотите удалять резервные файлы, вы можете использовать следующие методы:
- (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); } }
будьте осторожны, что это может быть очень медленно (зависит от того, сколько объектов в графе объектов).
здесь комбинированное решение для очистки основных данных.
- (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]); } } }
Если вы хотите пойти по маршруту удалить все объекты (что намного проще, чем сносить основной стек данных, но менее производительно), чем это лучшая реализация:
- (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
для выполнения удаления основного потока и уведомления о завершении. Вы можете отправить уведомление или что-то в блоке завершения, чтобы пузырь статус обратно в основной поток.
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() } } }
перебирает все основные объекты данных и очищает их
вот несколько упрощенная версия с меньшим количеством вызовов 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]; }
быстрое решение:
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) }
в качестве быстрой ссылки для сохранения поиска в другом месте-воссоздание постоянного хранилища после его удаления можно выполнить с помощью:
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { // do something with the error }
Спасибо за пост. Я последовал за ним, и это сработало для меня. Но у меня был еще один вопрос, который не был упомянут ни в одном из ответов. Поэтому я не уверен, что это был только я.
в любом случае, я думал, что опубликую здесь проблему и мой способ ее решить.
у меня было несколько записей в базе данных, я хотел очистить все чистое, прежде чем писать новые данные в БД, поэтому я сделал все, включая
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
и затем использовать
managedObjectContext
для доступа к базе данных (должно быть, сейчас пусто), каким-то образом данные все еще были там. Через некоторое время устранения неполадок, я обнаружил, что мне нужно сброситьmanagedObjectContext
,managedObject
,managedObjectModel
иpersistentStoreCoordinator
, прежде чем я используюmanagedObjectContext
для доступа к dabase. Теперь у меня есть чистая база данных для записи.
несколько хороших ответов на этот вопрос. Вот хороший краткий. Первые две строки удаляют базу данных 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]; }
вы также можете найти все имена сущностей, и удалить их по имя. Его более длинная версия, но работает хорошо, таким образом, вам не придется работать с persistence store
- (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" вернет все имена сущностей. Наконец, не забудьте сохранить.
принятый ответ верен с удалением URL с помощью NSFileManager правильно, но, как указано в iOS 5+ edit, постоянное хранилище не представлено только одним файлом. Для SQLite store это *.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];
Если вы используете
MagicalRecord
и иметь хранилище сохраняемости по умолчанию:мне не нравятся все решения, которые предполагают, что определенные файлы существуют и/или требуют ввода имен сущностей или классов. Это быстрый (2), безопасный способ удалить все данные из всех объектов. После удаления он будет воссоздать свежий стек тоже (я на самом деле не уверен, как neccessery эта часть).
это Годо для ситуаций стиля" выход", когда вы хотите удалить все, но есть рабочее хранилище и 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) } } }
использовать
+(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]; }
Я взял код Грушаля и для его ускорения использовал перечисление с параллельным режимом (
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); } }
вот моя версия 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 } }
работает со всеми версиями. Передайте имя сущности и повторите, чтобы удалить все записи и сохранить контекст.
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)") } }
iOS 10 и Swift 3
предполагая, что ваше имя сущности - "фото", и что вы создаете класс CoreDataStack...
func clearData() { do { let context = CoreDataStack.sharedInstance.persistentContainer.viewContext let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo") do { let objects = try context.fetch(fetchRequest) as? [NSManagedObject] _ = objects.map{.map{context.delete()}} CoreDataStack.sharedInstance.saveContext() } catch let error { print("ERROR DELETING : \(error)") } } }
вот хороший учебник о том, как использовать CoreData и как использовать этот метод. https://medium.com/compileswift/parsing-json-response-and-save-it-in-coredata-step-by-step-fb58fc6ce16f#.1tu6kt8qb
вот версия, которая удаляет все записи в каждой таблице у вас есть.
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)") } }