【问题标题】:iOS Core Data when to save context?iOS Core Data 何时保存上下文?
【发布时间】:2012-01-17 11:23:48
【问题描述】:

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

这对我来说有点太多了,所以我正在努力寻找更简单的出路。

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

阅读 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的回复后补充一个问题:这种方法在core data中合法吗?

-(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 ;
}

}

谢谢!

【问题讨论】:

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


    【解决方案1】:

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

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

    默认情况下,NSManagedObjectContext 创建和返回的对象是自动释放的。例如,如果您创建了一个新对象并想在表单中编辑它,您可以在创建对象之前调用 setRetainsRegisteredObjects: 并在托管对象上下文中调用 YES,这样它就会保留创建的对象,直到您完成它。请记住,不建议您自己管理NSManagedObjects 的生命周期——您应该让NSManagedObjectContext 来做。因此,考虑到这一点,您不必保留NSManagedObject。在保存操作之后,它被上下文注销并从内存中删除。你这边什么都不需要。

    回答更新的问题部分

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

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

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

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

    【讨论】:

    • 如果我理解正确的话,保存只会在创建完整的对象之后进行。所以如果我创建一个对象并设置它的所有属性,我可以保存。如果我稍后要触摸对象并“填充”它,我不必保存直到完成。这是正确的吗?
    • 您能否评论我添加到问题中的更新。如果使用这样的方法可能会导致我的指针悬空,我会徘徊。当我稍后尝试访问指针时?
    • 给你!并从第一条评论中回答您的问题。是的。这是正确的。每次更改对象的属性时都无需保存。一方面 - 它不是必需的 - 只要上下文创建它,您的对象就存在。另一个原因是这样的保存可能每次都会触及数据库,Apple 建议不要太频繁地触及闪存,因为闪存单元的磨损会增加并且会缩短用户设备的使用寿命。
    • 您能否为 coredata 推荐一个 Helper 类?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 2011-08-13
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多