由于并发和多线程,我随机崩溃核心数据。我知道核心数据不是线程安全的。我还找到了关于如何创建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 ;
}
}
谢谢!
答案 0 :(得分:17)
您不必在过程的早期保存上下文,尤其是当您想要在之后修改对象时。
在大多数情况下,您应该为要在数据库上执行的更改创建单独的NSManagedObjectContext
。因此,在其上创建对象,填写所需的属性,然后发送save
并使用主上下文执行整个mergeChangesFromContextDidSaveNotification:
技巧(最有可能在主线程上运行,因此使用performSelectorOnMainThread
。 ..消息)。
默认情况下,NSManagedObjectContext
创建并返回的对象是自动释放的。例如,如果您已创建了一个新对象并希望在表单中对其进行编辑,则可以在创建对象之前使用“是”对管理对象上下文调用setRetainsRegisteredObjects:
,因此它会保留创建的对象,直到您完成它。请注意,我们不建议您自行管理NSManagedObject
s生命周期 - 您应该让NSManagedObjectContext
执行此操作。因此,考虑到这一点,您不必保留NSManagedObject
。在保存操作之后,它将被上下文取消注册并从内存中删除。您无需担心任何事情。
如果您返回NSManagedObjectID
(使用[object objectID]
)而不是对象本身,那可能会更好。它允许通过上下文安全地处理对象,如果需要对象进行进一步编辑或数据检索(例如来自其他上下文),他们可以单独从商店中获取它。
即使您不保存上下文,新创建的对象也在那里,然后您可以决定是否要保留该对象。
另一方面保存后,如果上下文仍然存在,它可能会从内存缓存中返回给定NSManagedObjectID
的对象 - 而不会触及数据库。
另一方面;),在你的情况下,你可以非常安全地返回对象,因为创建它的NSManagedObjectContext
仍然存在,所以对象仍然存在,尽管已经在自动释放池中