iOS Core Data何时保存上下文?

Ale*_*one 19 iphone concurrency core-data objective-c ios

由于并发和多线程,我随机崩溃核心数据.我知道核心数据不是线程安全的.我还找到了关于如何创建ThreadedDataService以及为每个线程实例化单独上下文的其他几个答案.

这对我来说有点太多了,所以我试图找到一个更简单的方法.

我目前正在尝试的解决方案很简单:通过主线程保存数据.但是,现在出现了一个新问题:死锁.该应用程序变得无法响应,因为我对新NSManagedObject的每次插入后都会调用save.(这是我最好的猜测).

阅读App Delegate文档,我注意到它建议我在applicationWillTerminate中保存上下文.

我的问题是:对于每分钟插入新事件的长时间运行操作,并且用户不需要立即看到传播到所有控制器的更新,何时是保存上下文的好时机? 我觉得为每条记录保存上下文可能有点矫枉过正?

-(void)insertNewEvent
{


    // Create a new instance of the entity managed by the fetched results controller.
    NSManagedObjectContext *context = [self.fetchedResultsController.managedObjectContext];
    NSEntityDescription *entity = [[self.fetchedResultsControllerfetchRequest] entity];
    Event*newManagedObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

//use accessor methods to set default values

    // Save the context. > IS THIS REALLY NEEDED HERE?
    NSError *error = nil;
    if (![context save:&error])
    {


    }else
    {
        if(newManagedObject!=nil)
        {
            currentState= newManagedObject;
            [currentRecord addEvent:newManagedObject];
//Is this call needed?
            [self saveApplicationRecords];      
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我为所有托管对象定义了这些方法,如果我每10-15分钟在主线程上调用这样的方法来保存挂起的更改就足够了,而不是在每次插入记录后这样做?

-(void)saveApplicationRecords
{
     NSLog(@"saveApplicationRecords");
    NSManagedObjectContext *context = [self.applicationRecordsController.managedObjectContext];
    // Save the context.
    NSError *error = nil;
    if (![context save:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

    }

}
Run Code Online (Sandbox Code Playgroud)

阅读macbirdie的回复后的一个额外问题:这种方法在核心数据中是合法的吗?

-(Event*)insertAndReturnNewEventWithDate:(NSDate*)date_ type:(int)type
{
 NSManagedObjectContext *context = [self.dreamEventsController managedObjectContext];
    NSEntityDescription *entity = [[self.dreamEventsController fetchRequest] entity];
    DreamEvent *newManagedObject = (Event*)[NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

//handle properties

 NSError *error = nil;
    if (![context save:&error])
    {
return nil;

    }else
    {
return newManagedObject ;
}

}
Run Code Online (Sandbox Code Playgroud)

谢谢!

mac*_*die 17

您不必在过程的早期保存上下文,尤其是当您想要在之后修改对象时.

在大多数情况下,您应该NSManagedObjectContext为要在数据库上执行的更改创建单独的.因此,在其上创建对象,填写所需的属性,然后使用主上下文发送save和执行整个mergeChangesFromContextDidSaveNotification:技巧(最有可能在主线程上运行,因此使用performSelectorOnMainThread...消息).

默认情况下,创建并返回的对象NSManagedObjectContext是自动释放的.例如,如果您已创建新对象并希望在表单中对其进行编辑,则可以setRetainsRegisteredObjects:在创建对象之前使用YES 调用托管对象上下文,因此它将保留创建的对象,直到您完成它为止.请记住,不建议NSManagedObject您自己管理s'生命周期 - 您应该让它自己NSManagedObjectContext做.所以,考虑到这一点,你不必保留NSManagedObject.在保存操作之后,它将被上下文取消注册并从内存中删除.您无需任何操作.

回答更新的问题部分

如果你返回NSManagedObjectID(使用[object objectID])而不是对象本身可能会更好.它允许通过上下文安全地处理对象,并且如果需要对象进行进一步编辑或数据检索(例如,来自其他上下文),则它们可以单独从存储中获取它.

即使您不保存上下文,新创建的对象也在那里,然后您可以决定是否要保留该对象.

另一方面,在保存之后,如果上下文仍然存在,它可能会NSManagedObjectID从内存缓存中返回给定给您的对象- 而不会触及数据库.

在另一方面;),在你的情况下,你可以非常安全地返回对象,因为NSManagedObjectContext创建它仍然存在,所以该对象仍然存在,虽然已经在自动释放池中.

  • 你去吧!并从第一条评论中回答你的问题.是.那是对的.每次更改对象的属性时都不需要保存.对于一个 - 它不是必需的 - 只要创建它的上下文,您的对象就存在.另一个原因是这样的保存可能每次都会触及数据库,并且Apple建议不要经常触摸闪存存储器,因为闪存单元的磨损增加并且可能缩短用户设备的寿命. (2认同)