本文介绍了最好的办法要更新管理从异步Web服务响应对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个的NSManagedObjectContext 相关联的主线程( mainContext ),在那里我获取所有 NSManagedObject 我展示整个应用程序。

用户不编辑这些对象,但我从网络服务的更新。我定期执行这样的服务异步调用,他们告诉我哪我的管理对象已被删除(如果有的话),这其中有新的信息(如果有的话)进行更新,如果我需要插入新的对象。

所以,我需要首先获得所有服务的反应,然后检查什么样的变化我必须做出对管理对象,我已经在我的 mainContext 。而且我也需要执行,避免阻塞UI更新。

我在想约2的方式来管理这样的情景:


  1. 要在自己的核心数据专用队列使用完全分离 privateContext 堆到插入那里所有我从服务获取的对象。然后比较莫名其妙(如何?)和我在 mainContext ,并删除/修改是否有 mainContext

  2. 要在专用队列使用 privateContext ,但作为的 mainContext 的孩子。那么我需要通过孩子方面其父我有对象 mainContext (这可能吗?怎么样?),并在此背景下的孩子同时插入的对象,我从服务获取,然后比较并进行修改。

的办法什么是最好的还是恰当的呢?或者,也许这应该是一个不同的我,有没有想过?

在此先感谢

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


  • 仅使用 mainContext ,正如我解析服务的反应,而不是创建新的对象,只是让变化对 mainContext 一一...

  • 编辑2:另一种可能性:


  • 仅使用 privateContext ,得到的服务响应和创建新的对象。然后,也与此取 privateContext 已经存在(这将是相同 mainContext )。在这变化 privateContext 比较两组对象(最近从服务中创造和获取),保存这样的背景下,明确 mainContext 键,再取出在 mainContext 的所有对象。


  • 解决方案

    我不知道这是你一个完整的答案,但我的工作有点类似的情况。我已经采取的执行路径是使用子对象(所有的地方) - 还是更喜欢根据需要临时子上下文的

    我要提到的第一件事,但是,请务必使用 CoreData 调试功能建设成X $ C $℃。我做了第二次运行计划有

    -com.apple.CoreData.ConcurrencyDebug 1

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

     的NSManagedObjectContext * childContext = [[的NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
       [小孩setParentContext:parentObjectContext];

    然后,每当我需要通过从父母到孩子,我最终会做什么:

      [小孩objectWithID:(对象的父上下文)

    或我最终会做

      __块AHRS_RPYL * RET;[自getChildContext] performBlockAndWait:^ {    RET = [NSEntityDescription insertNewObjectForEntityForName:@RPYLinManagedObjectContext:自getChildContext]];// ...很多code的
    }];

    我不能说我真的爱这种做法,我有点与它卡住的那一刻但它似乎工作不够好。

    之间的大多数我的视图控制器我有一个

      @synthesize managedObjectContext;

    在我的 prepareForSegue

      //通过,managedObjectContext
    - (无效)prepareForSegue:(UIStoryboardSegue *)赛格瑞发件人:(ID)发送{    // dispatch_async(dispatch_get_main_queue(),^ {
        //如果目标是VC能够采取德setManagedObjectContext方法目前的ObjectContext会传承下去。
        如果([segue.destinationViewController respondsToSelector:@selector(setManagedObjectContext :)]){
            [segue.destinationViewController performSelector:@选择(setManagedObjectContext :)
                                                  withObject:self.managedObjectContext];    }其他{        的NSLog(@顺着接下去到控制器[%@]不支持通过managedObjectContext,[原因请看destinationViewController]);
        }
        //});
    }

    摘要


    • 我和你的第二个选择,选择工作,它是可行的,虽然它在我的真实想法感到一种沉闷。事实是,我们正在研究改用境界,而不是 CoreData 因为无论你如何看待它 CoreData 不是最线程友好的选择。

    UDPATES

    保存code

    其实我救孩子语境每50消息,并于母公司每250它看起来像(没有触及这个年龄code)。我不能保证这是做事情最好的正确的方法,但它的工作,它并保持光盘访问到最低限度。我得到的消息很多像20+第二,所以我想做这个栈类型。你可能不在乎

    (self.getChild())返回子方面 - 它的旧的code我离开这里。

     如果(MSGCOUNT%50 == 0){
                    //儿童保存!                //的NSLog(@保存SDatas);
                    __block的NSManagedObjectContext * currentChild = [个体经营getChildContext]
                    [个体经营incChildContext]                //亲子保存方法
                    [currentChild performBlock:^ {
                        NSError *错误;
                        如果(![currentChild节省:放大器;错误]){
                            的NSLog(@\\ n错误=>%@ \\ n,[错误localizedDescription]);
                            的NSLog(@错误=>%@,[错误USERINFO]);
                            [NSException提高:@数据库写入错误格式:@%@%@,[错误localizedDescription],[错误USERINFO]];                        //中止();
                        }                    如果(MSGCOUNT%250℃; 5){                        [parentObjectContext performBlock:^ {
                                NSError *错误;
                                如果(![parentObjectContext节省:放大器;错误]){
                                    的NSLog(@\\ n错误=>%@ \\ n,[错误localizedDescription]);
                                    的NSLog(@错误=>%@,[错误USERINFO]);
                                    [NSException提高:@数据库写入错误格式:@%@%@,[错误localizedDescription],[错误USERINFO]];                                //中止();
                                }
                            }];
                        }                    [currentChild复位]
                    }];
                }

    删除

      [childContext performBlock:^ { //将code地段
     //建立一个查询集,我们要杀死记录
    // END很多code的
    [childContext DeleteObject的:消息];
            如果(I%modFactor == 0){
                self.percentDone = I /总记录;            的NSLog(@。1F%保存...,self.percentDone * 100);
                NSError *错误;
                如果(![childContext节省:放大器;错误]){
                    的NSLog(@\\ n错误=>%@ \\ n,[错误localizedDescription]);
                    的NSLog(@错误=>%@,[错误USERINFO]);
                    [NSException提高:@数据库写入错误格式:@%@%@,[错误localizedDescription],[错误USERINFO]];                //中止();
                }            [parentContext performBlock:^ {
                    NSError * errrror;
                    如果(![parentContext节省:放大器; errrror]){
                        的NSLog(@\\ n错误=>%@ \\ n,[错误localizedDescription]);
                        的NSLog(@错误=>%@,[错误USERINFO]);
                        [NSException提高:@数据库写入错误格式:@%@%@,[错误localizedDescription],[错误USERINFO]];                    //中止();
                    }
                }];
            }}];

    ...

    再次 - 就像我之前说这可能不是做事情的最好方法,但我有一个父/子堆栈和它的工作。这是第一个iOS应用程序,我写的一个,做一遍我会撑船核心数据,并使用别的东西。

    我们有,所以当我们使用一个单一堆栈它使得用户界面非常缓慢极高的更新速度。以父/子迁移缓慢 - 是我做一遍,我认为它会去更顺畅,因为我写了许多辅助函数来处理一些本(或只是使用SWIFT)

    好运。

    I have an NSManagedObjectContext associated to main thread (mainContext), where I fetch all the NSManagedObject I show throughout the app.

    Users don't edit these objects, but I get updates from web services. I periodically perform asynchronous calls to such services, and they "tell" me which of my managed objects have to be deleted (if any), which of them have to be updated with new information (if any), and if I need to insert new objects.

    So, I need to firstly get the responses of all the services and then check what changes I have to make to the managed objects I already have in my mainContext. And I also need to perform the updates avoiding blocking the UI.

    I was thinking about 2 ways to manage this scenario:

    1. To use a completely separated privateContext in a private queue with its own Core Data stack to insert there all the objects I get from services. Then compare somehow (how?) with the objects I have in mainContext, and delete/modify/insert objects that are there in mainContext.
    2. To use a privateContext in a private queue, but being a child of the mainContext. I'd then need to pass the child context the objects I have in its parent mainContext (is this possible? how?), and at the same time insert in this child context the objects I get from services, and then compare and perform changes.

    What of the approaches would be the best or the appropriate one? Or maybe should it be a different one I haven't thought about?

    Thanks in advance

    EDIT: Could this be another possible way?:

    1. Only use the mainContext and, as I'm parsing the responses of the services, instead of creating the new objects just make changes on mainContext one by one...

    EDIT 2: Another possibility?:

    1. Only use the privateContext, get the services responses and create the new objects. Then, also fetch with this privateContext all the objects that already existed (and that would be the same as the objects in mainContext). Make changes in this privateContext comparing the two sets of objects (the recently created from services and the fetched), save this context, clear mainContext and re-fetch all objects in mainContext.
    解决方案

    I'm not sure this is a full answer for you but I'm working on a somewhat similar situation. The implementation path I've taken is to use child objects (all over the place) - or more like temporary child context's as needed.

    The first thing I should mention, however, is make sure to use the CoreData debug functionality build into XCOde. I made a second Run-Scheme that has

    -com.apple.CoreData.ConcurrencyDebug 1

    On application init I have my normal NSManagedObjectContext - which is passed around to my background networking thread.

    NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
       [child setParentContext:parentObjectContext];
    

    Then whenever I need to pass something from parent to child I end up doing:

    [child objectWithID:(object-in-parent-context)]
    

    or I end up doing

    __block AHRS_RPYL * ret;
    
    [[self getChildContext] performBlockAndWait:^{
    
        ret = [NSEntityDescription insertNewObjectForEntityForName:@"RPYL" inManagedObjectContext:[self getChildContext]];
    
    // ... lots of code
    }];
    

    I can't say I really "love" this approach and I'm sort of stuck with it for the moment however it does seem to work well enough.

    Between most of my view controllers I have a

    @synthesize managedObjectContext;
    

    And in my prepareForSegue method

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

    Summary

    • I've worked with your second choice option and it is doable although it feels kind of clunky in my honest opinion. The truth is we are looking into switching to Realm instead of CoreData because no matter how you look at it CoreData is not the most threading friendly option.

    UDPATES

    Save Code

    I actually save to the child context every 50 messages and to the parent every 250 it looks like (haven't touched this code in ages). I can't promise this is the best correct way to do things but it does work and it does keep disc access to a minimum. I am getting A LOT of messages like 20+ a second so i wanted to do this stack type. You may not care

    (self.getChild()) returns the child context - its older code i left here.

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

    Deleting

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

    ...

    Again - like i said before this may not be the best way of doing things but i do have a parent/child stack and it does work. This was one of the first iOS apps I wrote and to do it over again i'd punt on core data and use something else.

    We had an extremely high update rate so when we were using a single stack it was making the UI very slow. The migration to parent/child was slow - were i to do it again I think it would have gone smoother because i'd write many helper functions to deal with some of this (or just use swift).

    good luck.

    这篇关于最好的办法要更新管理从异步Web服务响应对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    09-03 07:09