从异步Web服务响应更新托管对象的最佳方法是什么?

时间:2015-09-27 07:50:12

标签: ios core-data asynchronous concurrency nsmanagedobjectcontext

我有一个NSManagedObjectContext与主要帖子(mainContext)相关联,在那里我获取了整个应用中显示的所有NSManagedObject

用户不要编辑这些对象,但我会从Web服务获得更新。我会定期对这些服务执行异步调用,并且他们会告诉"我必须删除哪些托管对象(如果有的话),必须使用新信息(如果有的话)更新哪些托管对象,以及是否需要插入新对象。

因此,我需要首先获取所有服务的响应,然后检查我必须对我mainContext中已有的托管对象进行哪些更改。我还需要执行更新,以避免阻止UI。

我正在考虑两种方法来管理这种情况:

  1. 在具有自己的Core Data堆栈的私有队列中使用完全分离的privateContext,以插入从服务获得的所有对象。然后以某种方式(如何?)与mainContext中的对象进行比较,并删除/修改/插入mainContext中的对象。
  2. 要在私人队列中使用privateContext,但要成为mainContext的子级。然后我需要传递子对象我在其父mainContext中的对象(这可能吗?怎么样?),同时在这个子上下文中插入我从服务获得的对象,然后比较并执行更改。
  3. 哪种方法最好或最合适?或者也许它应该是我想不到的另一个?

    提前致谢

    编辑:这可能是另一种可能的方式吗?:

    1. 仅使用mainContext,因为我正在解析服务的响应,而不是创建新对象,只需逐个对mainContext进行更改......
    2. 编辑2:另一种可能性?:

      1. 仅使用privateContext,获取服务响应并创建新对象。然后,还使用此privateContext获取已存在的所有对象(这与mainContext中的对象相同)。在此privateContext中进行更改,比较两组对象(最近从服务和已提取的对象创建),保存此上下文,清除mainContext并重新获取mainContext中的所有对象。 / LI>

1 个答案:

答案 0 :(得分:0)

我不确定这是一个完整的答案,但我正在处理类似的情况。我采用的实现路径是使用子对象(遍布整个地方) - 或者更像是临时子上下文所需的。

但是,我要提到的第一件事是确保使用 CoreData 调试功能构建到XCOde中。我制作了第二个具有

的Run-Scheme

-com.apple.CoreData.ConcurrencyDebug 1

enter image description here

在应用程序初始化我有我的正常NSManagedObjectContext - 它被传递给我的后台网络线程。

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]);
    }
    //    });
}

摘要

  • 我已经使用了你的第二选择,虽然在我的诚实意见中感觉有点笨拙,但它是可行的。事实是我们正在考虑切换到Realm而不是CoreData,因为无论你如何看待它CoreData都不是最友好的线程选择。

UDPATES

保存代码

实际上,我每50条消息保存到子上下文,并且每250条保存到父级(看起来很久没有触及此代码)。我不能保证这是最好的正确方法,但它确实有效,并且确实将光盘访问保持在最低限度。我得到了很多像20+一样的消息,所以我想做这种堆栈类型。你可能不在乎

(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应用程序之一,并且我再次尝试使用核心数据并使用其他内容。

我们有一个非常高的更新率,所以当我们使用单个堆栈时,它使UI非常慢。迁移到父/子的速度很慢 - 如果我再次这样做,我认为它会更顺畅,因为我会编写许多辅助函数来处理其中一些(或者只是使用swift)。

祝你好运。