0

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

     });

这是 fetch 方法:

 -(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];

}

我究竟做错了什么?

4

1 回答 1

0

您在这里缺少一些基本人员。

第一的。改变您在多线程环境中使用托管对象上下文的方式。第二。你不需要创建NSFetchedResultsController来执行获取请求。

那么,假设((MyAppDelegate )([UIApplication sharedApplication].delegate)).managedObjectContext返回具有 * NSMainQueueConcurrencyType** 并发类型的主托管对象上下文,那么您的背景和 fetch 方法应该是什么样子:

     // 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];

 });

和 fetch 方法

-(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];
}
于 2013-02-14T09:29:00.990 回答