- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经仔细阅读了 SO 上的所有相关线程,但仍然对如何从多个线程对核心数据对象进行更改而不必在每次更改后进行保存感到困惑。
我正在开发一个不断与服务器通信的应用程序。该应用程序使用 Core Data 进行存储,并在一些 View Controller 中使用 NSFetchedResultsController 来从持久性存储中获取数据。通常当用户执行某个操作时,会触发网络请求。在发送网络请求之前,通常应对相关的Core Data对象进行一些更改,并且在服务器响应时,将对这些Core Data对象进行更多更改。
最初,所有核心数据操作都是在同一个 NSManagedObjectContext
中的主线程上完成的。一切都很好,只是当网络流量很高时,应用程序可能会变得无响应几秒钟。显然这是 Not Acceptable ,因此我考虑将一些核心数据操作移至后台运行。
我尝试的第一种方法是创建一个 NSOperation 对象来处理每个网络响应。在 NSOperation 对象的 main 方法中,我设置了一个专用的 MOC,进行一些更改,并在最后提交更改。
- (void)main
{
@try {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Create a dedicated MOC for this NSOperation
NSManagedObjectContext * context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[APP_DELEGATE persistentStoreCoordinator]];
// Make change to Core Data objects
// ...
// Commit the changes
NSError *error = nil;
if ([context hasChanges] && ![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
// Release the MOC
[context release];
// Drain the pool
[pool drain];
}
@catch (NSException *exception) {
// Important that we don't rethrow exception here
NSLog(@"Exception: %@", exception);
}
}
主线程上的 MOC 已为 NSManagedObjectContextDidSaveNotification
注册。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
因此,当后台上下文提交更改时,主 MOC 将收到通知,然后合并更改:
- (void)backgroundContextDidSave:(NSNotification *)notification
{
// Make sure we're on the main thread when updating the main context
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:) withObject:notification waitUntilDone:NO];
return;
}
// Merge the changes into the main context
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
但是,正如我之前提到的,我还需要从主 MOC 对核心数据对象进行更改。每一项更改通常都很小(例如更新对象中的一个实例变量),但可能会有很多更改。所以我真的不想在每次更改后都保存主要的 MOC。但如果我不这样做,在将更改从后台 MOC 合并到主 MOC 时就会遇到问题。由于两个 MOC 都有未保存的更改,因此会发生合并冲突。设置合并策略也没有帮助,因为我想保留两个 MOC 的更改。
一种可能性是也使用 NSManagedObjectContextDidSaveNotification
注册后台 MOC,但这种方法对我来说听起来像是糟糕的设计。每次更改后我仍然需要保存主要 MOC。
我尝试的第二种方法是从在永久后台线程上运行的专用后台上下文中执行所有核心数据更改。
- (NSThread *)backgroundThread
{
if (backgroundThread_ == nil) {
backgroundThread_ = [[NSThread alloc] initWithTarget:self selector:@selector(backgroundThreadMain) object:nil];
// Actually start the thread
[backgroundThread_ start];
}
return backgroundThread_;
}
// Entry point of the background thread
- (void)backgroundThreadMain
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// We can't run the runloop unless it has an associated input source or a timer, so we'll just create a timer that will never fire.
[NSTimer scheduledTimerWithTimeInterval:DBL_MAX target:self selector:@selector(ignore) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
// Create a dedicated NSManagedObjectContext for this thread.
backgroundContext_ = [[NSManagedObjectContext alloc] init];
[backgroundContext_ setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
[pool drain];
}
因此,每当我需要从主线程更改 Core Data 时,我都必须从主线程获取 objectID,然后传递给后台线程来执行更改。当后台上下文保存时,更改将被合并回主 MOC。
- (void)addProduct:(Product *)product toCatalog:(Catalog *)catalog;
将更改为:
- (void)addProduct:(NSManagedObjectID *)productObjectId toCatalog:(NSManagedObjectID *)catalogObjectId
{
NSArray * params = [NSArray dictionaryWithObjects:productObjectId, catalogObjectId, nil];
[self performSelector:(addProductToCatalogInBackground:) onThread:backgroundThread_ withObject:params waitUntilDone:NO];
}
但这看起来很复杂而且丑陋。编写这样的代码似乎首先就否定了使用 Core Data 的用处。另外,我仍然需要在每次更改后保存 MOC,因为如果不先将新对象保存到数据存储中,我就无法获取新对象的 objectId。
我觉得我错过了一些东西。我真的希望有人能对此有所启发。谢谢。
最佳答案
NSManagedObjectContext
只是一个便笺簿。保存它的行为会将暂存器中的更改向下移动到 NSPersistentStoreCoordinator 并可能向下移动到磁盘。一个 MOC 可以了解另一个 MOC 的更改的唯一方法是通过 NSPercientStoreCoordinator。因此需要保存。然而,在下一版本的 iOS 中,保存的成本要低得多。
如果您必须符合 iOS4 或更低版本,那么保存是唯一的选择。但是,您可以加载保存内容并降低执行频率,具体取决于应用程序的设计。如果您要导入数据,请在导入完成时保存或以导入内部的逻辑单元保存。不需要每次输入后都保存,这样很浪费。
顺便说一句,我建议使用 NSOperation
实例,而不是直接使用 NSThread
实例。他们更容易合作并且表现更好。
此外,您不需要将 Objective-C 代码包装在 try/catch block 中。很少有事情会抛出异常;尤其是在 iOS 上。
最后,我建议看一下 my post on CIMGF关于在后台线程上导入。
关于iphone - 如何从不同线程更改 Core Data 对象,而无需在每次更改后保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7730648/
SO亲爱的 friend 们: 2014 年 3 月 18 日。我正在处理一种情况,在使用 ng-repeat 时,数组内的元素(我从 Json 字符串中获取)更改了原始顺序。 需要明确的是,数组中的
有很多问题询问如何在 JavaScript 单击处理程序中更改 div 的类,例如,此处:Change Div style onclick .我理解得很好(只需更改 .className),并且它有效
我从access导入了一个数据库到mysql,但其中一个表的列名“股数”带有空格,但我尝试更改、替换甚至删除列名,但失败了。任何人都可以帮助解决这一问题 String UpdateQuary = "U
我正在做一个随机的学校元素。 目前,我有一个包含两个 CSS 的页面。一种用于正常 View ,一种用于残障人士 View 。 此页面还包括两个按钮,它们将更改使用的样式表。 function c
我需要使用 javascript 更改 HTML 元素中的文本,但我不知道该怎么做。 ¿有什么帮助吗? 我把它定义成这样: Text I want to change. 我正在尝试这样做: docum
我在它自己的文件 nav_bar.shtml 中有一个主导航栏,每个其他页面都包含该导航栏。这个菜单栏是一个 jQuery 菜单栏(ApyCom 是销售这些导航栏的公司的名称)。导航栏上的元素如何确定
我正在摆弄我的代码,并开始想知道这个变化是否来自: if(array[index] == 0) 对此: if(!array[index] != 0) 可能会影响任何代码,或者它只是做同样的事情而我不需
我一直在想办法调整控制台窗口的大小。这是我正在使用的函数的代码: #include #include #define WIDTH 70 #define HEIGHT 35 HANDLE wHnd;
我有很多情况会导致相同的消息框警报。 有没有比做几个 if 语句更简单/更好的解决方案? PRODUCTS BOX1 BOX2 BOX3
我有一个包含这些元素的 XELEMENT B Bob Petier 19310227 1 我想像这样转换前缀。 B Bob Pet
我使用 MySQL 5.6 遇到了这种情况: 此查询有效并返回预期结果: select * from some_table where a = 'b' and metadata->>"$.countr
我想知道是否有人知道可以检测 R 中日期列格式的任何中断的包或函数,即检测日期向量格式更改的位置,例如: 11/2/90 12/2/90 . . . 15/Feb/1990 16/Feb/1990 .
我希望能够在小部件显示后更改 GtkButton 的标签 char *ButtonStance == "Connect"; GtkWidget *EntryButton = gtk_button_ne
我正在使用 Altera DE2 FPGA 开发板并尝试使用 SD 卡端口和音频线路输出。我正在使用 VHDL 和 C 进行编程,但由于缺乏经验/知识,我在 C 部分遇到了困难。 目前,我可以从 SD
注意到这个链接后: http://www.newscientist.com/blogs/nstv/2010/12/best-videos-of-2010-progress-bar-illusion.h
我想知道在某些情况下,即使剧本任务已成功执行并且 ok=2,ansible 也会显示“changed=0”。使用 Rest API 和 uri 模块时会发生这种情况。我试图找到解释但没有成功。谁能告诉
这个问题已经有答案了: 已关闭12 年前。 Possible Duplicate: add buttons to push notification alert 是否可以在远程通知显示的警报框中指定有
当您的 TabBarController 中有超过 5 个 View Controller 时,系统会自动为您设置一个“更多” View 。是否可以更改此 View 中导航栏的颜色以匹配我正在使用的颜
如何更改.AndroidStudioBeta文件夹的位置,默认情况下,该文件夹位于Windows中的\ .. \ User \ .AndroidStudioBeta,而不会破坏任何内容? /编辑: 找
我目前正在尝试将更具功能性的编程风格应用于涉及低级(基于 LWJGL)GUI 开发的项目。显然,在这种情况下,需要携带很多状态,这在当前版本中是可变的。我的目标是最终拥有一个完全不可变的状态,以避免状
我是一名优秀的程序员,十分优秀!