我想從sqlite持久性存儲的後臺線程上的核心數據做一個簡單的提取。核心數據後臺提取失敗,直到多餘的插入後
該方法是來自返回對象的RESTful API調用的響應。如果找到這個對象,它想更新它。如果沒有找到,它想插入它。
儘管如此,第一次在每次重新啓動應用程序之後調用api時,獲取失敗(即使我可以在sql數據庫中看到該對象)並插入一個新的託管對象。但是,該插入不會導致創建新對象。仍然只有一個對象!
第二次調用api時,獲取成功找到對象,一切正常。
所以謂詞是正確的,模型中沒有錯別字。
這裏有後臺方法的基礎:
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];
}
我在做什麼錯?
感謝馬克,我做了更改,現在可以正常工作。一些額外信用的問題:我是否仍需要合併ChangeChanges?保存子上下文時是否對父上下文進行更改?另外,我仍然將所有這些包裝在dispatch_async調用中。使用performBlock是不必要的? – 2013-02-14 16:00:44
如果您保存子上下文,它只是將您的更改推入父上下文。最後,要查看持久存儲中的更改,您需要保存父上下文。爲了做到這一點,你可以使用下面的代碼片段:[backgroundContext performBlock:^ {Errror * error = nil; [backgroundContext save:&error]; [parentManagedObjectContext performBlockAndWait:^ {Errors * parentError = nil; [parentManagedObjectContext save:&parentError]; }]; }]; – 2013-02-14 16:42:13