Answers:
您仍然可以使用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 +更新
随着iOS 5和OS X 10.7中引入外部二进制存储(allowsExternalBinaryDataStorage或存储在外部记录文件中),仅删除storeURLs指向的文件是不够的。您将留下外部记录文件。由于这些外部记录文件的命名方案不是公开的,所以我还没有一个通用的解决方案。– 2012年5月8日an0 23:00
您可以删除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);
}
}
我选择逐表进行处理的原因是,这使我在进行编程时确认删除表的内容是明智的,并且没有要保留的数据。
这样做比仅删除文件要慢得多,如果此方法花费的时间太长,我将更改为文件删除。
使用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,请参阅此问题。
资料来源:
moc.performBlockAndWait({ () -> Void in
...内})
。
我编写了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
类中,该类负责(除其他事项外)在null时创建persistentStore。
我从HomeViewController类的Button事件中的核心数据中删除了所有数据:这篇文章对我有很大帮助,我认为我会有所作为。
-(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中声明了一个属性。(不必担心我用于保存和加载的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];
MR_truncateAll
?
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)
}
}
}
[针对悬赏要求新答案的最新答案]
查看先前的答案,
但是,有另一种类似的方法可以删除有效的持久性存储。关键是将持久性存储文件放在其自己的不包含其他任何内容的子目录中。不要只是将其粘贴在documents目录(或任何位置)中,而是为持久性存储创建一个新的子目录。该目录的内容最终将是持久性存储文件,日记文件和外部二进制文件。如果您想删除整个数据存储区,请删除该目录,它们都将消失。
在设置持久性存储时,您将执行以下操作:
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];
这将以递归方式删除自定义子目录和其中的所有Core Data文件。
仅当您尚未将持久性存储区与其他重要数据存储在同一文件夹中时,此方法才有效。像documents目录,其中可能包含其他有用的内容。如果这是你的情况,你可以通过查找文件,您得到相同的效果都希望保持和消除其他一切。就像是:
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.
}
这种方法可能容易出错。您必须绝对确定自己知道要保留的每个文件,否则可能会删除重要数据。另一方面,您可以删除外部二进制文件,而无需实际知道用于存储它们的文件/目录名称。
这是清除核心数据的组合解决方案。
- (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)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)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 *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
使用该方法一样进行初始化,否则会出现错误:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
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()
}
}
}
遍历所有核心数据实体并清除它们
感谢您的帖子。我遵循它,它为我工作。但我有另一个未在任何答复中提及的问题。所以我不确定是否只是我。
无论如何,以为我会在这里发布问题以及解决问题的方式。
我在数据库中有几条记录,我想在将新数据写入db之前清除所有内容,因此我做了包括
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
然后用来managedObjectContext
访问数据库(现在应该是空的),数据仍然存在。一段时间后故障排除,我发现我需要重置managedObjectContext
,managedObject
,managedObjectModel
和
persistentStoreCoordinator
,以前我用managedObjectContext
访问dabase。现在,我有一个干净的数据库要写入。
这是一个稍微简化的版本,对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)
}
let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
作为将搜索保存到其他位置的快速参考-删除后重新创建持久性存储可以使用以下方法完成:
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}
这个问题有几个好的答案。这是一个很好的简洁。前两行删除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];
}
您还可以找到所有实体名称,并按名称删除它们。它的版本较长,但效果很好,因此您不必使用持久性存储
- (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”将返回所有实体名称。最后,不要忘记保存。
接受的答案是正确的,通过NSFileManager删除URL是正确的,但是正如iOS 5+ edit中所述,持久性存储并不仅由一个文件表示。对于SQLite存储,它是* .sqlite,*。sqlite-shm和* .sqlite-wal ...幸运的是,由于iOS 7+,我们可以使用method
[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];
这是一个删除您每个表中的每个记录的版本。
斯威夫特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)")
}
}
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()
}
}
适用于所有版本。传递实体名称并进行遍历以删除所有条目并保存上下文。
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的实现看起来像这样(假设您有一个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)
}
}
}
这种方法的一个优点是它更加简单明了,尤其是当您在核心数据中有大量实体的数据记录负载时。在这种情况下,删除批处理请求将占用大量内存。
假设您正在使用 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)
}
}
}
用这个
+(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];
}
我采用了Grouchal的代码,并使用并发模式(NSEnumerationConcurrent
)进行了加速,与for循环相比,它的速度要快一些(在我的应用中,我为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);
}
}
这是我的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
}
}
NSBatchDeleteRequest
。stackoverflow.com/a/31961330/3681880