从asynchronousWeb服务响应更新托pipe对象的最佳方法?
我有一个NSManagedObjectContext
关联到主线程( mainContext
),在那里我获取我显示整个应用程序的所有NSManagedObject
。
用户不要编辑这些对象,但我从Web服务获取更新。 我定期对这些服务执行asynchronous调用,并且“告诉”我要删除哪些pipe理对象(如果有的话),哪些必须用新信息更新(如果有的话),以及是否需要插入新的对象。
所以,我需要首先获得所有服务的响应,然后检查我必须对我的mainContext
已有的托pipe对象所做的更改。 而且我还需要执行更新以避免阻止UI。
我正在考虑两种方法来pipe理这种情况:
- 在私有队列中使用一个完全独立的
privateContext
和它自己的核心数据栈来插入所有从服务中获得的对象。 然后以某种方式(如何?)与mainContext
的对象进行比较,并删除/修改/插入mainContext
对象。 - 在专用队列中使用
privateContext
,但是作为mainContext
的子mainContext
。 然后,我需要传递子对象的父对象mainContext
中的对象(这是可能的?如何?),同时在这个子对象中插入从服务获得的对象,然后比较和执行更改。
哪些方法是最好的或适当的? 或者,也许应该是一个我没有想过的不同的?
提前致谢
编辑:这可能是另一种可能的方式?
- 只使用
mainContext
,而我正在parsing服务的响应,而不是创build新的对象,只需要在mainContext
逐一进行更改…
编辑2:另一种可能性?
- 只有使用
privateContext
,获取服务响应并创build新的对象。 然后,也可以用这个privateContext
获取所有已经存在的对象(和mainContext
的对象一样)。 在这个privateContext
比较两组对象(最近创build的服务和获取的),保存此上下文,清除mainContext
并重新获取mainContext
所有对象。
我不确定这是一个完整的答案,但我正在做一个类似的情况。 我所采取的实现path是使用子对象(遍布整个地方) – 或者更像是需要的临时子上下文。
我应该提到的第一件事是确保将CoreDatadebuggingfunction内置到XCOde中。 我做了第二个跑步计划
-com.apple.CoreData.ConcurrencyDebug 1
在应用程序初始化我有我的正常的NSManagedObjectContext
– 这是传递到我的后台networking线程。
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [child setParentContext:parentObjectContext];
然后,无论何时我需要传递一些从父母到孩子的事情,我最终都会做:
[child objectWithID:(object-in-parent-context)]
或者我最终在做
__block AHRS_RPYL * ret; [[self getChildContext] performBlockAndWait:^{ ret = [NSEntityDescription insertNewObjectForEntityForName:@"RPYL" inManagedObjectContext:[self getChildContext]]; // ... lots of code }];
我不能说我真的“喜欢”这个方法,而且我暂时坚持这个方法,但它确实工作得很好。
在我的大多数视图控制器之间,我有一个
@synthesize managedObjectContext;
在我的prepareForSegue
方法
// Pass on managedObjectContext - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // dispatch_async(dispatch_get_main_queue(), ^{ // If the destination VC is able to take teh setManagedObjectContext method the current objectContext will be passed along. if ([segue.destinationViewController respondsToSelector:@selector(setManagedObjectContext:)]) { [segue.destinationViewController performSelector:@selector(setManagedObjectContext:) withObject:self.managedObjectContext]; } else { NSLog(@"Segue to controller [%@] that does not support passing managedObjectContext", [segue destinationViewController]); } // }); }
概要
- 我已经与你的第二select的select,这是可行的,虽然它在我的诚实的意见感觉有点笨拙。 事实是,我们正在考虑切换到Realm而不是
CoreData
因为不pipe你怎么看它,CoreData
都不是最易于使用的选项。
UDPATES
保存代码
我实际上每50条消息就会保存到子上下文中,并且每隔250个字符就会保存到父项(在年龄上并没有触及这个代码)。 我不能保证这是做最好的正确的方式,但它确实工作,它确保光盘访问最小。 我得到了很多消息像20+秒,所以我想要做这个堆栈types。 你可能不在乎
(self.getChild())返回子上下文 – 我留在这里的旧代码。
if (msgCount % 50 == 0) { // Child Save! // NSLog(@"Saving SDatas"); __block NSManagedObjectContext *currentChild = [self getChildContext]; [self incChildContext]; // Parent-Child save methodology [currentChild performBlock:^{ NSError *error; if (![currentChild save:&error]) { NSLog(@"\n error => %@ \n", [error localizedDescription]); NSLog(@" error => %@ ", [error userInfo]); [NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]]; // abort(); } if (msgCount % 250 < 5) { [parentObjectContext performBlock:^{ NSError *error; if (![parentObjectContext save:&error]) { NSLog(@"\n error => %@ \n", [error localizedDescription]); NSLog(@" error => %@ ", [error userInfo]); [NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]]; // abort(); } }]; } [currentChild reset]; }]; }
删除
[childContext performBlock:^{ // LOTS OF CODE // to build a query set of the records we want to kill // End lots of code [childContext deleteObject:msg]; if (i % modFactor == 0) { self.percentDone = i / totalRecords; NSLog(@"%.1f Saving ...", self.percentDone * 100); NSError *error; if (![childContext save:&error]) { NSLog(@"\n error => %@ \n", [error localizedDescription]); NSLog(@" error => %@ ", [error userInfo]); [NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]]; // abort(); } [parentContext performBlock:^{ NSError *errrror; if (![parentContext save:&errrror]) { NSLog(@"\n error => %@ \n", [error localizedDescription]); NSLog(@" error => %@ ", [error userInfo]); [NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]]; // abort(); } }]; } }];
…
再次 – 就像我之前所说,这可能不是做事的最佳方式,但我有一个父/子堆栈,它的工作。 这是我写的第一个iOS应用程序之一,并再次做我会踢核心数据和使用别的东西。
我们有一个非常高的更新率,所以当我们使用一个单一的堆栈,使得用户界面非常缓慢。 迁移到父母/孩子是慢的 – 我再次这样做,我认为它会更顺利,因为我会写很多帮助函数来处理一些(或只是使用迅速)。
祝你好运。