核心数据背景提取失败,直到多余的插入

时间:2013-02-13 23:18:01

标签: ios core-data

我正在尝试从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];

}

我做错了什么?

1 个答案:

答案 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];
}