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

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

问题描述

我从网络服务器获取数据,在名为 backgroundMOC 的子私有背景上下文中处理它.它是链接到主 UI 的 mainMOC 的子级,因此保存在 backgroundMOC 上会触发 UI 更改.mainMOCmasterMOC 的子节点,它是一个与持久存储相关联的私有后台队列,因此保存在主服务器上会保存到磁盘.

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 上调用了 getPermanentIDsForObjects,它是 mainMOC 的子级,它是 masterMOC 的子级.我切换了它,以便获得 mainMOC 上的 ID,它解决了我所有的问题(目前).我难道不应该在子上下文中调用获取 PermIds 吗?

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...

虽然您应该能够要求永久 ID,但您应该只在已插入的对象上要求它们.

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,尽管您可以有一个单独的 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.

编辑

回应斯文...

如果您正在创建新的、复杂的图形,那么您需要在创建后立即获得一个永久 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.

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

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