2014-10-27 61 views
2

我有一种方法,允许用户导出我的Core Data model中的所有数据的.csv文件。在执行fetchRequest以获取存储的结果后,我正在使用精彩的CHCSV Parser。一旦创建了.csv,它就会附加到电子邮件并从设备中导出。这一切工作正常,当我删除数据时出现问题。重置核心数据模型中的所有保存的数据

我正在使用一种有点流行的技术来删除我的数据(通过流行我的意思是它已被推荐在我已经研究了很多堆栈溢出的答案)。我只需获取所有对象并逐个删除它们。

// Create fetchRequest 
NGLSAppDelegate *appDelegate = (NGLSAppDelegate *)[[UIApplication sharedApplication]delegate]; 
NSManagedObjectContext *context = [appDelegate managedObjectContext]; 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"NGLS" 
                 inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 
NSError *error; 
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; 

// Delete objects 
for (Model *results in fetchedObjects) { 
    [context deleteObject:(id)results]; 
    NSLog(@"NGLS objects deleted"); 
}; 

model很简单,只有两个entities,所以我使用相同的代码为其他Admin entity了。这一切都很好,所有对象都被删除,我可以通过执行另一个fetchRequest来确认这一点,它会返回每个对象的计数entity - 两者的计数均为零。当我尝试在执行删除操作后将数据保存回entity时,会发生此问题。

带上述代码的ViewController是一个“Admin”控制屏幕,用户可以在该屏幕上登录并导出数据。因此,当在,这里的用户登录的代码保存:

// Save login details 
    [_managedObjectAdmin setValue:user forKey:@"userLogin"]; 
    [_managedObjectAdmin setValue:site forKey:@"siteLocation"]; 

    NSError *error; 
    [[self.managedObjectAdmin managedObjectContext] save:&error]; 

我那么执行上述fetchRequest,并按下“导出”按钮时,导出所有数据。这是完成后,当我尝试登录同一ViewController,输出为:

2014-10-27 12:43:49.653 NGLS[19471:607] <NSManagedObject: 0x7a8c2460> (entity: Admin; id: 0x7a82e3e0 <x-coredata://3C9F3807-E314-439C-8B73-3D4459F85156/Admin/p30> ; data: <fault>) 

如果我导航回到另一个ViewController(使用我navigation controller),然后返回到“管理”的控制屏幕和尝试再次登录,我得到这个输出:

2014-10-27 12:44:04.530 NGLS[19471:607] *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x7a82e3e0 <x-coredata://3C9F3807-E314-439C-8B73-3D4459F85156/Admin/p30>'' 

(我可以发布完整的日志,如果请求)。

我尝试了很多事情来尝试解决此问题。核心数据是复杂的,我不太明白我需要做什么来解决这个问题。我试图删除persistentStore并再次创建它,并与managedObjectContext相同,但没有任何我已经尝试过的工作。我在AppDelegate实施resetStore方法来删除和重建商店如下:

- (void)resetStores { 
    NSError *error; 
    NSURL *storeURL = [[_managedObjectContext persistentStoreCoordinator] URLForPersistentStore:[[[_managedObjectContext persistentStoreCoordinator] persistentStores] lastObject]]; 
    // lock the current context 
    [_managedObjectContext lock]; 
    [_managedObjectContext reset];//to drop pending changes 
    //delete the store from the current managedObjectContext 
    if ([[_managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[_managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:&error]) 
    { 
     // remove the file containing the data 
     [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 
     //recreate the store like in the appDelegate method 
     [[_managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store 
    } 
    [_managedObjectContext unlock]; 
} 

而且也试过这个方法:

- (NSPersistentStoreCoordinator *)resetPersistentStore 
{ 
    NSError *error = nil; 
    if ([_persistentStoreCoordinator persistentStores] == nil) 
     return [self persistentStoreCoordinator]; 

    _managedObjectContext = nil; 

    NSPersistentStore *store = [[_persistentStoreCoordinator persistentStores] lastObject]; 

    if (![_persistentStoreCoordinator removePersistentStore:store error:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    // Delete file 
    if ([[NSFileManager defaultManager] fileExistsAtPath:store.URL.path]) { 
     if (![[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:&error]) { 
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
      abort(); 
     } 
    } 

    // Delete the reference to non-existing store 
    _persistentStoreCoordinator = nil; 
    NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator]; 

    return r; 
} 

但这些都不能工作。我发现的工作是在导出完成后,关闭并重新打开应用程序,所有工作都正常。我试图找出在关闭核心数据时关闭/打开应用程序时发生什么过程,但我不知道要寻找什么。我已经研究了很多堆栈溢出的问题,并尝试了所有的解决方案,但没有为我工作。我真的需要一些帮助,否则我将不得不强制用户在导出完成后通过exit(0);命令退出应用程序(因为它没有提交到App Store,它的内部员工)虽然我不想要这种解决方案,但肯定有一种方法可以重置我的数据库并继续使用该应用程序,而无需每次都关闭它。提前致谢。

参考文献:
Deleting all records from Core Data
Reset a Core Data persistent store
How do I delete all objects from my persistent store in Core Data

+1

如何设置'self.managedObjectAdmin'?或者我应该说,你是如何创造它的? – pbasdf 2014-10-27 14:01:30

+0

它是在我的'viewDidLoad'方法中创建的,我所需要做的就是在导出后再次调用该方法以重新创建'managedObject'。请参阅下面的答案。这样简单的解决方案! – rosshump 2014-10-27 14:05:54

回答

1

我已成功通过简单地刷新视图,以解决这一问题。通过在导出完成后调用我的viewDidLoad方法,我创建了一个新的managedObject,可以正常使用,无需离开该ViewController或完全退出应用程序。

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view from its nib 

    // Create fetchRequest 
    NGLSAppDelegate *appDelegate = (NGLSAppDelegate *)[[UIApplication sharedApplication]delegate]; 
    NSManagedObjectContext *context = [appDelegate managedObjectContext]; 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Admin" inManagedObjectContext:context]; 
    [fetchRequest setEntity:entity]; 

    NSError *error = nil; 
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; 

    // Fetch last object 
    Model *admin = [fetchedObjects lastObject]; 

    // Populate login fields with last stored details 
    if (admin.userLogin == nil) { 
     //NSLog(@"Login empty"); 
    } else { 
     self.usernameField.text = admin.userLogin; 
     self.siteLocationField.text = admin.siteLocation; 
    } 

    // Create new managed object using the Admin entity description 
    NSManagedObject *ManagedObjectAdmin; 
    ManagedObjectAdmin = [NSEntityDescription insertNewObjectForEntityForName:@"Admin" 
                 inManagedObjectContext:context]; 
    // Declare managed object 
    self.managedObjectAdmin = ManagedObjectAdmin; 

    // Save context 
    NSError *saveError = nil; 
    [context save:&saveError]; 

// ... more stuff 
} 

解决方案一直很简单。我将离开这个问题/答案,以便其他人可以从中受益,如果他们发现自己处于我的处境。谢谢。

编辑:导出后,在任何地方重新创建managedObjectAdmin,没有特别需要调用viewDidLoad方法。导出完成后,我可以简单地创建新的managedObject并保存context,并继续正常使用该应用程序,而无需先导航到另一个ViewController或重新启动该应用程序。