iOS Core Data何时保存上下文?

时间:2011-12-10 16:06:26

标签: iphone objective-c ios core-data concurrency

由于并发和多线程,我随机崩溃核心数据。我知道核心数据不是线程安全的。我还找到了关于如何创建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];      
        }
    }

}

我为所有托管对象定义了这样的方法,如果我每隔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]);

    }

}

阅读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 ;
}

}

谢谢!

1 个答案:

答案 0 :(得分:17)

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

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

默认情况下,NSManagedObjectContext创建并返回的对象是自动释放的。例如,如果您已创建了一个新对象并希望在表单中对其进行编辑,则可以在创建对象之前使用“是”对管理对象上下文调用setRetainsRegisteredObjects:,因此它会保留创建的对象,直到您完成它。请注意,我们不建议您自行管理NSManagedObject s生命周期 - 您应该让NSManagedObjectContext执行此操作。因此,考虑到这一点,您不必保留NSManagedObject。在保存操作之后,它将被上下文取消注册并从内存中删除。您无需担心任何事情。

回答更新的问题部分

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

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

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

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