我正在尝试从sqlite持久性存储中的后台线程上的核心数据进行简单的获取。
该方法是RESTful api调用的响应,它返回一个对象。如果找到此对象,则需要更新它。如果没有找到,它想插入它。
但是,每次重新启动应用程序后第一次调用api时,提取失败(即使我可以在sql数据库中看到对象)并插入新的托管对象。但是,此插入不会导致创建新对象。仍然只有一个对象!
第二次调用api时,fetch成功找到了对象,一切都很顺利。
因此谓词是正确的,模型中没有拼写错误。
以下是背景方法的基础知识:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Create a MOC for this background thread.
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundContext setPersistentStoreCoordinator:((MyAppDelegate *)([UIApplication sharedApplication].delegate)).persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:backgroundContext];
// This is the returned value from the api call.
NSDictionary *responseDict = [completedOperation.responseString JSONValue];
NSString *venueName = [responseDict valueForKey:@"venueName"];
// VenueDescription is a managed object model.
VenueDescription *venueDesc = [[DatabaseManager sharedDatabaseManager] fetchVenueDescriptionForVenueName:venueName context:backgroundContext];
if (!venueDesc) { // venueDesc is nil the first time even though the object exists.
// This insert does NOT create a new object.
venueDesc = [NSEntityDescription insertNewObjectForEntityForName:@"VenueDescription" inManagedObjectContext:backgroundContext];
}
if (venueDesc) {
venueDesc.venueName = venueName;
/*.... code to update venueDesc from the dictionary....*/
[backgroundContext refreshObject:venueDesc mergeChanges:YES];
}
[[DatabaseManager sharedDatabaseManager] saveContext:backgroundContext];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:backgroundContext];
[backgroundContext release];
});
这是获取方法:
-(VenueDescription *)fetchVenueDescriptionForVenueName:(NSString *)venueName context:(NSManagedObjectContext *)context {
NSEntityDescription * entity = [NSEntityDescription entityForName:@"VenueDescription" inManagedObjectContext:context];
if (!entity) return nil;
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSManagedObjectResultType];
[fetchRequest setFetchLimit:1];
NSSortDescriptor *nameSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"venueName" ascending:YES];
NSArray *sortDescriptorArray = [NSArray arrayWithObject:nameSortDescriptor];
[nameSortDescriptor release];
[fetchRequest setSortDescriptors:sortDescriptorArray];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"venueName LIKE %@", venueName];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *controller = [[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil] autorelease];
NSError *error = nil;
[controller performFetch:&error];
if (error) NSLog(@"Error fetching Venue Descriptions: %@", error);
[fetchRequest release];
if ([controller.fetchedObjects count] == 0) return nil;
return [controller.fetchedObjects objectAtIndex:0];
}
我做错了什么?
答案 0 :(得分:0)
你在这里缺少一些基本的工作人员。
首先。更改在多线程环境中使用托管对象上下文的方式。 第二。您无需创建 NSFetchedResultsController 来执行获取请求。
那么假设((MyAppDelegate )([UIApplication sharedApplication] .delegate))。managedObjectContext 返回你的后台和获取方法应该是什么样子带有* NSMainQueueConcurrencyType **并发类型的主要托管对象上下文:
// Create a MOC for this background thread.
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[backgroundContext setParentContext:((MyAppDelegate *)([UIApplication sharedApplication].delegate)).managedObjectContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:backgroundContext];
NSDictionary *responseDict = [completedOperation.responseString JSONValue];
[backgroundContext performBlock:^{
// This is the returned value from the api call.
NSString *venueName = [responseDict valueForKey:@"venueName"];
// VenueDescription is a managed object model.
VenueDescription *venueDesc = [[DatabaseManager sharedDatabaseManager] fetchVenueDescriptionForVenueName:venueName context:backgroundContext];
if (!venueDesc) { // venueDesc is nil the first time even though the object exists.
// This insert does NOT create a new object.
venueDesc = [NSEntityDescription insertNewObjectForEntityForName:@"VenueDescription" inManagedObjectContext:backgroundContext];
}
if (venueDesc) {
venueDesc.venueName = venueName;
/*.... code to update venueDesc from the dictionary....*/
[backgroundContext refreshObject:venueDesc mergeChanges:YES];
}
[[DatabaseManager sharedDatabaseManager] saveContext:backgroundContext];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:backgroundContext];
[backgroundContext release];
});
和获取方法
-(VenueDescription *)fetchVenueDescriptionForVenueName:(NSString *)venueName context:(NSManagedObjectContext *)context {
NSEntityDescription * entity = [NSEntityDescription entityForName:@"VenueDescription" inManagedObjectContext:context];
if (!entity) return nil;
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSManagedObjectResultType];
[fetchRequest setFetchLimit:1];
NSSortDescriptor *nameSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"venueName" ascending:YES];
NSArray *sortDescriptorArray = [NSArray arrayWithObject:nameSortDescriptor];
[nameSortDescriptor release];
[fetchRequest setSortDescriptors:sortDescriptorArray];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"venueName LIKE %@", venueName];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray* fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (error) NSLog(@"Error fetching Venue Descriptions: %@", error);
[fetchRequest release];
return [fetchedObjects lastObject];
}