Jody:CoreData和线程

关于Jody的问题,在jody's threading中经常遇到, 我使用以下代码从 Web 服务加载数据并将其存储在 Core Data DB 中。

我使用以下代码从 Web 服务加载数据并将其存储在 Core Data DB 中。

    dispatch_queue_t fetchQ = dispatch_queue_create("fetcher", NULL);
dispatch_async(fetchQ, ^{
    NSArray *list = [WebService loadData];
    dispatch_sync(dispatch_get_main_queue(), ^{
        if (list != nil) {
            for (NSDictionary *data in list) {
                NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:appDelegate.coreDataDatabase.managedObjectContext];
                NSFetchRequest *request = [[NSFetchRequest alloc] init];
                [request setEntity:entityDescription];
                NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id = %i", [[data objectForKey:@"id"] integerValue]];
                [request setPredicate:predicate];
                NSError *error = nil;
                NSArray *data = [appDelegate.coreDataDatabase.managedObjectContext executeFetchRequest:request error:&error];
                Object *object = [data objectAtIndex: 0];
                if (object == nil) {
                    object = [NSEntityDescription insertNewObjectForEntityForName:@"Object" inManagedObjectContext:appDelegate.coreDataDatabase.managedObjectContext];
                    object.id = [NSNumber numberWithInteger:[[data objectForKey:@"id"] integerValue]];
                }
                object.name = [data objectForKey:@"name"];
            }
            [appDelegate.coreDataDatabase saveToURL:appDelegate.coreDataDatabase.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];
        }
    });
});
dispatch_release(fetchQ);

代码简化了,但它应该表示顺序。对 web 服务的访问在后台运行。之后,在主线程中调用商店。实际上应该 OK,对吧?

不幸的是,整体并不是在所有设备上都能正常工作。在我所有的设备和大多数其他设备上,没有问题。在一些但显然是这样,因为不幸的是,商店里有一些负面的 Bewertugnen 和几个问题。问题是他在 DB 中发现了一个已经存在的记录,而不是不断地进行新的投资

谢谢你的帮助斯特凡

1

我很难理解你的实际问题。

在一些但显然是这样的,因为不幸的是,商店里有一些负面的 Bewertugnen 和几个问题。问题是他在 DB 中发现了一个已经存在的记录,而不是不断地进行新的投资

所以我将采取我最好的猜测。

从代码中,我假设您正在使用 UIManagedDocument。

您不应该直接保存UIManagedDocument(saveToUrl)。相反,您应该让它处理自动保存,因为它会适当地这样做。

如果您在UIManagedDocument上激活了NSUndoManager,则无需执行任何操作。所有操作都将自动保存。如果您没有撤消管理器,则需要戳它以使其知道它具有脏数据。您可以使用:

[managedDocument updateChangeCount:UIDocumentChangeDone];

但是,请注意,UIManagedDocument使用嵌套上下文,并且有一些与插入新对象相关的错误。即,持久性 ID 没有正确地推回子上下文。我对你的问题的假设是,你得到重复的数据条目,因为这个。

这个 SO 问题在一定程度上解决了这个问题。

Core Data could not fullfil fault for object after obtainPermanantIDs

基本上,你有几个选择,考虑到你想继续UIManagedDocument。首先,获取永久 ID。替换此行:

[appDelegate.coreDataDatabase saveToURL:appDelegate.coreDataDatabase.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:nil];

这个(当然-处理错误-这只是通过 0):

NSManagedObjectContext *moc = appDelegate.coreDataDatabase.managedObjectContext;
[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:0];
[appDelegate.coreDataDatabase updateChangeCount:UIDocumentChangeDone];

你的代码似乎没有一个非常复杂的对象图,所以这应该足够了。

另一种选择是导入到一个单独的 MOC(UIManagedDocument父上下文的子),并在导入完成时重新获取主上下文。

使用您的代码示例,一个简单的方法是这样的...

dispatch_queue_t fetchQ = dispatch_queue_create("fetcher", NULL);
dispatch_async(fetchQ, ^{
    NSArray *list = [WebService loadData];
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
    moc.parentContext = appDelegate.coreDataDatabase.managedObjectContext.parentContext;
    for (NSDictionary *data in list) {
        NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Object" inManagedObjectContext:moc];
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        [request setEntity:entityDescription];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id = %i", [[data objectForKey:@"id"] integerValue]];
        [request setPredicate:predicate];
        NSError *error = nil;
        NSArray *data = [moc executeFetchRequest:request error:&error];
        Object *object = [data objectAtIndex: 0];
        if (object == nil) {
            object = [NSEntityDescription insertNewObjectForEntityForName:@"Object" inManagedObjectContext:moc];
            object.id = [NSNumber numberWithInteger:[[data objectForKey:@"id"] integerValue]];
        }
        object.name = [data objectForKey:@"name"];
    }
    // Save the MOC you just loaded everything into
    [moc save:&error]; // handle error...
    // Save the parent MOC, which is also the parent of your main MOC
    moc = moc.parentContext;
    [moc performBlock:^{
        [moc save:&error]; // handle error
        // When all the saves are done, run on the main queue and just refetch
        // all the entities that were inserted.
        dispatch_async(dispatch_get_main_queue(), ^{
            // Here, use appDelegate.coreDataDatabase.managedObjectContext
            // to refetch the objects that were altered.  If you are using a
            // table view or FRC just issue a refetch of the data and the
            // main MOC will get everything that was modified.
        });
    }];
});
dispatch_release(fetchQ);
0

如果您在主线程上创建了上下文,那么对它的每次访问也必须在主线程上(假设 pre-ios 5 配置-Core Data 支持 3 种模式后 iOS 5)。

您可以创建一个串行调度队列,在那里创建 moc,并通过该队列漏斗对它的所有访问。

我自己刚刚转换为使用 iOS5 中的私有队列功能,在这种情况下,每次访问都是通过 '[moc 执行块...]' 完成的-我花了不到 1 小时进行转换,并且代码实际上变得更干净(我一直在使用前面提到的串行队列)。

本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处

(75)
Atlas数据库:将mongoatlas数据库迁移到 Azure数据湖存储
上一篇
Idea编译class文件:Linux中的IntelliJIDEA编译加速
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(33条)