我使用以下代码从 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 中发现了一个已经存在的记录,而不是不断地进行新的投资
谢谢你的帮助斯特凡
我很难理解你的实际问题。
在一些但显然是这样的,因为不幸的是,商店里有一些负面的 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);
如果您在主线程上创建了上下文,那么对它的每次访问也必须在主线程上(假设 pre-ios 5 配置-Core Data 支持 3 种模式后 iOS 5)。
您可以创建一个串行调度队列,在那里创建 moc,并通过该队列漏斗对它的所有访问。
我自己刚刚转换为使用 iOS5 中的私有队列功能,在这种情况下,每次访问都是通过 '[moc 执行块...]' 完成的-我花了不到 1 小时进行转换,并且代码实际上变得更干净(我一直在使用前面提到的串行队列)。
本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处
评论列表(33条)