获取PermanentID后,核心数据无法满足对象的错误 [英] Core Data could not fulfill fault for object after obtainPermanentIDs

查看:142
本文介绍了获取PermanentID后,核心数据无法满足对象的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从网络服务器获取数据,在名为 backgroundMOC 的子私有背景上下文中处理它。它是 mainMOC 的子项,它链接到主UI,因此保存 backgroundMOC 会触发UI更改。 mainMOC masterMOC 的子项,这是一个绑定到持久存储的私有后台队列,因此保存在master保存到磁盘。

I'm getting data from a webserver, processing it on a child private background context called backgroundMOC. It is a child of a mainMOC which is linked to the main UI, so saving on the backgroundMOC triggers UI changes. The mainMOC is a child of a masterMOC which is a private background queue tied to the persistent store, so saving on the master saves to disk.

我现在所做的是接收数据,在 backgroundMOC 上创建新对象,然后保存 backgroundMOC (以便UI更新),保存 mainMOC ,(这样我几乎可以保存到磁盘),并保存 masterMOC (这样我最终可以写入磁盘)。问题是,当对象通过提取的结果控制器出现在UI中时, objectId 仍然是临时的。

What I do now is receive data, create new objects on backgroundMOC, then save backgroundMOC (so that the UI updates), save mainMOC, (so that I can almost save to disk), and save masterMOC (so that I can finally write to disk). The problem is that when the object appears in the UI via a fetched results controller, the objectId is still a temporary one.

这会导致重复行问题,如果我从服务器收到相同的数据(偶然),我的 backgroundMOC 不知道该对象已经存在,因为它尚未被分配永久ID,因此它创建了另一个对象。当我重新启动应用程序时,重复的对象消失了,所以我知道这只是id映射的问题。

This causes problems with duplicate row issues, where if I receive the same data from the server (by accident), my backgroundMOC does not know that this object already exists because it has not been assigned a permanent id, so it creates another object. When I restart the app, the duplicate object disappears, so I know it's just an issue with id mapping.

所以我想我可能会尝试

[backgroundMOC obtainPermanentIDsForObjects:backgroundMOC.registeredObjects.allObjects error:nil];

在保存之前(我在保存之后也尝试过)。但是,出于某种原因,调用此行会抛出异常:

before saving at all (I've tried after saving too). However, for some reason, calling this line throws an exception:


CoreData无法解决...

CoreData could not fulfill a fault for...

如果您有任何可能引导我朝正确方向前进的提示,请分享。谢谢

If you have any hints that might lead me in the right direction, please share. Thanks

编辑:好的,所以最初我在backgroundMOC上调用了acquirePermanentIDsForObjects,后者是mainMOC的子节点,它是一个子节点。 masterMOC。我切换它以便我获得mainMOC上的ID,它解决了我所有的问题(现在)。我是不是应该在子上下文中调用obtainPermIds?

Ok so initially I was calling obtainPermanentIDsForObjects on the backgroundMOC, which is a child of the mainMOC, which is a child of the masterMOC. I switched it so that I obtain the ids on the mainMOC, and it solved all my problems (for now). Was I never supposed to call obtainPermIds on the child context?

推荐答案

这是一个已知的错误(嵌套的上下文在获取永久ID时没有新的对象被保存了)可以,并且应该在即将发布的版本中修复...

This is a known bug (nested contexts not getting permanent IDs when new objects are saved)could, and supposed to be fixed in an upcoming release...

你应该可以要求永久身份证,但是你应该只问对于已经插入的对象的它们。

You should be able to ask for permanent IDs though, but you should only ask for them on the objects that have been inserted.

[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:0];

您必须在保存MOC之前执行此操作,因为如果您在未获取永久ID的情况下保存,则临时ID将传播到父上下文。例如,在您保存到mainMoc,然后获取IDS的情况下,backgroundMOC仍然具有临时ID,因此将来保存将创建重复数据。

You must do this before saving the MOC though, because if you save without obtaining permanent IDs, the temporary IDs are propagated to parent contexts. For example, in your case where you save to the mainMoc, then obtain the IDS, the backgroundMOC still has the temporary IDs, so future saves from it will create duplicate data.

请注意,获取永久ID一直到数据库,但是如果你在主MOC的子MOC中进行,那么在发生这种情况时你根本不应该阻塞主线程。

Note that obtaining permanent IDs goes all the way to the database, but if you are doing it in a child MOC of the main MOC, you should not block the main thread at all while this is happening.

所以,在你从最低级别的MOC中保存时,你应该有效地拥有这样的东西(当然有适当的错误处理)......

So, in your save from your lowest level MOC, you should effectively have something like this (with appropriate error handling, of course)...

[backgroundMoc performBlock:^{
    [backgroundMoc obtainPermanentIDsForObjects:backgroundMoc.insertedObjects.allObjects error:0];
    [backgroundMoc save:0];
    [mainMoc performBlock:^{
       [mainMoc save:0];
        [masterMoc performBlock:^{
            [masterMoc save:0];
        }];
    }];
}];

如果你愿意,你可以玩其他一些游戏。

There are some other games you can play, if you want.

在NSManagedObject上提供类似于此的类别...

Provide a category on NSManagedObject similar to this...

@implementation NSManagedObject (initWithPermanentID)
- (id)initWithEntity:(NSEntityDescription *)entity insertWithPermanentIDIntoManagedObjectContext:(NSManagedObjectContext *)context {
    if (self = [self initWithEntity:entity insertIntoManagedObjectContext:context]) {
        NSError *error = nil;
        if (![context obtainPermanentIDsForObjects:@[self] error:&error]) {
            @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
        }
    }
    return self;
}

+ (NSArray*)createMultipleObjects:(NSUInteger)count withEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)context {
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
    for (NSUInteger i = 0; i < count; ++i) {
        [array addObject:[[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context]];
    }
    NSError *error = nil;
    if (![context obtainPermanentIDsForObjects:array error:&error]) {
        @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo];
    }
    return array;
}
@end

现在,在第一个,你付钱进入数据库并为每个创建的实体创建一个ID,但它并没有那么多,并且它发生在后台线程中,每次下降都很短......

Now, in the first one, you are paying to go into the database and create an ID for each entity created, but it's not that much, and it's happening in a background thread, and each dip is short...

哦,这不是最好的,但它提供了有用的。此外,第二个创建同一个对象的多个,并同时抓取它们的永久ID。

Oh well, it's not the best, but it has provided useful. In addition, the second creates multiple of the same object, and grabs their permanent IDs at the same time.

您还可以使用直接连接到PSC的MOC,以及注意DidChange事件,但这与旧方法相同。

You can also use a MOC directly connected to the PSC, and watch for DidChange events, but that's the same as the old way.

不幸的是,你不能只有一个单独的MOC来发出持久ID请求并传递ObjectID,尽管你可以在DB中有一个单独的MOC制作原型对象,并为你提供它们的ObjectID。

Unfortunately, you can't have a separate MOC just make persistentID requests and pass the ObjectID, though you can have a separate MOC making prototype objects in the DB, and giving you the ObjectID of them.

原型工厂是一种相当常见的模式,如果你走这条路线,当最终的错误修复到达时,很容易做出微小的改变。

A prototype factory is a fairly common pattern, and if you go that route, it's very easy to make a minor change when the eventual bug fixes get here.

编辑

回应Sven ...

In response to Sven...

如果要创建新的复杂图形,则需要在创建后立即获取永久ID。要减少商店的点击次数,你应该全部创建,然后一次获取ID,然后开始连接它们。

If you are creating new, complex graphs, then you need to obtain a permanent ID immediately after creation. To decrease the number of hits to the store, you should create them all, then obtain the IDs at once, then start hooking them up.

老实说,这一切都是为了解决当前存在的错误,这些错误值得解决中小型更新。当修复错误时,你的代码将是相同的(没有获得)。因此,我建议使用此方法进行较小的导入。

Honestly, all this is to get around the bugs that currently exist, which are worth working around for small-to-medium sized updates. Your code will be the same (sans the obtain) when the bugs are fixed. So, I suggest this method for smaller imports.

如果您正在进行大规模更新,我建议使用旧方法。创建一个直接连接到PSC的新MOC。在那里进行所有更改,并让您的实时上下文从这些DidSave通知中合并。

If you are doing a large scale update, I suggest using the "old" method. Create a new MOC directly connected to the PSC. Make all your changes there, and have your "live" contexts just merge from those DidSave notifications.

最后,关于永久ID的数据库影响。丢弃MOC是可以的。磁盘被点击,元数据被更改,但对象没有被保留。

Finally, on the database impact of permanent IDs. It is OK to discard the MOC. The disk is hit, and the metadata is changed, but the objects are not persisted.

老实说,我没有做大的测试,看看是否有空的空间因此,你可能想要这样做并与我一起回来。

Honestly, I did not do a large test to see if there is any empty space as a result, though, so you may want to do that and get back with me.

查看磁盘上的实际数据库文件大小,然后创建10000个对象,然后获取持久性ID,释放MOC,然后再次查看大小。

Look at the actual database file size on disk, then create 10000 objects, then obtain persistent IDs, release the MOC, and look at the size again.

如果有影响,您可以尝试删除对象,或对数据库运行真空经过大量更新,看看是否有效。

If there is an impact, you can try deleting the objects, or run a vacuum on the database after large updates to see if that works.

如果你要创建许多你可能扔掉的对象,那么就没有必要打到数据库了。您可能只想直接附加到PSC并使用旧的忠实通知。

If you are going to be creating lots of objects that you may just throw away, then there is no need to hit the database. You may want to just attach directly to the PSC and use the old faithful notifications.

这篇关于获取PermanentID后,核心数据无法满足对象的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆