iOS Core Data 何时保存上下文?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8457847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS Core Data when to save context?
提问by Alex Stone
I'm having random crashes with core data due to concurrency and multithreading. I know that core data is not thread safe. I also found a couple other answers on how to create a ThreadedDataService and instantiate separate context for each thread.
由于并发和多线程,我的核心数据随机崩溃。我知道核心数据不是线程安全的。我还找到了一些关于如何创建 ThreadedDataService 并为每个线程实例化单独上下文的其他答案。
This is a bit too much for me to swallow at the moment, so I'm trying to find an easier way out.
这对我来说现在有点太多了,所以我试图找到一个更简单的出路。
The solution that I'm trying at the moment is simple: saving data through the main thread.However, now a new issue arises: deadlock. The app becomes unresponsive because each of my insertions of a new NSManagedObject is followed by a call to save. (that's my best guess).
我目前尝试的解决方案很简单:通过主线程保存数据。但是,现在出现了一个新问题:死锁。该应用程序变得无响应,因为我每次插入新 NSManagedObject 后都会调用保存。(这是我最好的猜测)。
Reading the App Delegate documentation, I noticed that it advises me to save context in applicationWillTerminate.
阅读 App Delegate 文档时,我注意到它建议我在 applicationWillTerminate 中保存上下文。
My question is this: For a long running operation that inserts new events every minute, and the user is not required to see updates propagated to all controllers immediately, when is it a good time for me to save the context?I'm getting a feeling that saving context for each record may be an overkill?
我的问题是:对于每分钟插入新事件的长时间运行的操作,并且用户不需要立即看到更新传播到所有控制器,什么时候是我保存上下文的好时机?我有一种感觉,为每条记录保存上下文可能有点矫枉过正?
-(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];
}
}
}
I have methods like these defined for all of my managed objects, is it enough if I call such method on a main thread every 10-15 minutes to save pending changes, rather than doing so after each record insertion?
我为我的所有托管对象定义了这样的方法,如果我每 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]);
}
}
An extra question after reading macbirdie's response: is this kind of method legal in core data?
看了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 ;
}
}
Thank you!
谢谢!
采纳答案by macbirdie
You don't have to save the context that early in the process, especially when you want to modify the object afterwards.
您不必在流程的早期保存上下文,尤其是当您想在之后修改对象时。
In most cases you should create a separate NSManagedObjectContext
for the changes you're about to perform on the database. So create objects on it, fill out the properties needed, then send save
and perform the whole mergeChangesFromContextDidSaveNotification:
trick with the main context (most likely running on the main thread, so using performSelectorOnMainThread
... message).
在大多数情况下,您应该NSManagedObjectContext
为将要对数据库执行的更改单独创建一个。因此,在其上创建对象,填写所需的属性,然后使用主上下文发送save
并执行整个mergeChangesFromContextDidSaveNotification:
技巧(很可能在主线程上运行,因此使用performSelectorOnMainThread
...消息)。
By default an object created and returned by NSManagedObjectContext
is autoreleased. If you've created a new object and want to edit it in a form sheet for example, you can call setRetainsRegisteredObjects:
with YES to the managed object context before creating the object, so it holds on to the object created until you're done with it. Remember that it's not recommended to manage the NSManagedObject
s' lifecycle on your own - you should let the NSManagedObjectContext
do it. So, having that in mind, you don't have to retain the NSManagedObject
. After the save operation it's unregistered by the context and removed from memory. Nothing is required on your side.
默认情况下,创建和返回的对象NSManagedObjectContext
是自动释放的。例如,如果您创建了一个新对象并希望在表单中对其进行编辑,则可以setRetainsRegisteredObjects:
在创建对象之前使用 YES调用托管对象上下文,因此它会保留创建的对象,直到您完成它. 请记住,不建议NSManagedObject
您自己管理s 的生命周期 - 您应该让其NSManagedObjectContext
去做。因此,考虑到这一点,您不必保留NSManagedObject
. 在保存操作之后,它被上下文取消注册并从内存中删除。你不需要任何东西。
Answer to updated question part
回答更新的问题部分
It would be probably better if you returned an NSManagedObjectID
(using [object objectID]
) instead of the object itself. It allows to safely dispose of the object by the context and if one needs the object for further editing or data retrieval (e.g. from other contexts), they can fetch it from the store separately.
如果您返回一个NSManagedObjectID
(using [object objectID]
) 而不是对象本身可能会更好。它允许通过上下文安全地处理对象,如果需要对象进行进一步编辑或数据检索(例如从其他上下文),他们可以单独从存储中获取它。
Even if you don't save the context, the newly created object is there and then you can decide if you want to keep the object or not.
即使您不保存上下文,新创建的对象也在那里,然后您可以决定是否要保留该对象。
After saving on the other hand, if the context still exists, it may return the object with given NSManagedObjectID
to you from memory cache - without touching the database.
另一方面,保存后,如果上下文仍然存在,它可能会返回NSManagedObjectID
从内存缓存中提供给您的对象- 而不会触及数据库。
On yet another hand ;), in your case, you can pretty much safely return the object, since the NSManagedObjectContext
creating it still exists, so the object will still exist as well, although already in the autorelease pool.
另一方面;),在你的情况下,你可以非常安全地返回对象,因为NSManagedObjectContext
创建它仍然存在,所以对象仍然存在,尽管已经在自动释放池中。