核心数据对象循环更新

Posted

技术标签:

【中文标题】核心数据对象循环更新【英文标题】:Core data objects update through loop 【发布时间】:2014-01-07 02:09:48 【问题描述】:

我有一个tableView 显示core-data objects。在同一个视图上有五个按钮。每个按钮操作都应该更新对象的属性值。 例如,我将向您展示我必须更新属性“isDone”:

- (IBAction)allDoneAction:(id)sender 

    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    int i=0;
    for (NSManagedObject *mo in context)
    
        [mo setValue:@"Done" forKey:@"isDone"];i++;
    

    [managedObjectContext save:nil];


此方法抛出以下异常:

NSManagedObjectContext countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x9a6b0a0
2014-01-06 19:01:43.862 To-Do Pro[679:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObjectContext countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x9a6b0a0'

我需要什么来避免异常并获得所需的更新? 这是我的 NSFetchedResultsController:

- (NSFetchedResultsController *)fetchedResultsController

  if (fetchedResultsController) return fetchedResultsController;

  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
  NSEntityDescription *entity = 
               [NSEntityDescription entityForName:@"FavoriteThing" 
                           inManagedObjectContext:managedObjectContext];

  [fetchRequest setEntity:entity];

  NSSortDescriptor *sortDescriptor = 
              [[NSSortDescriptor alloc] initWithKey:@"displayOrder" 
                                          ascending:YES];

  NSArray *sortDescriptors = [[NSArray alloc] 
                              initWithObjects:sortDescriptor, nil];
    //SOLO TO-DOS DE TODAY


    todayDate = [NSDate date];

    NSCalendar* calendar = [NSCalendar currentCalendar];
    NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:todayDate]; // Get necessary date components




    NSNumber *yearBuscado = [NSNumber numberWithLong:[components year]];
    NSNumber *mesBuscado = [NSNumber numberWithLong:[components month]];
    NSNumber *diaBuscado = [NSNumber numberWithLong:[components day]];

   // NSString *tipourgente = @"Urgent";
   // NSString *tipocolor = @"Yellow";

    NSString *textoNotDone = @"Not done";
    NSString *textoNotDeleted = @"Not deleted";

    NSPredicate *yearPredicate = [NSPredicate predicateWithFormat:@"todoYear == %@", yearBuscado];
    NSPredicate *monthPredicate = [NSPredicate predicateWithFormat:@"todoMonth == %@", mesBuscado];
    NSPredicate *dayPredicate = [NSPredicate predicateWithFormat:@"todoDay == %@", diaBuscado];
    NSPredicate *notDonePredicate = [NSPredicate predicateWithFormat:@"isDone== %@", textoNotDone];
    NSPredicate *notDeletedPredicate = [NSPredicate predicateWithFormat:@"isSemiDeleted==%@", textoNotDeleted];
    // NSPredicate *urgentPredicate = [NSPredicate predicateWithFormat:@"urgent == %@", tipourgente];
   // NSPredicate *colorPredicate = [NSPredicate predicateWithFormat:@"color == %@", tipocolor];

  [fetchRequest setSortDescriptors:sortDescriptors];






  NSPredicate *busqueda = [NSCompoundPredicate andPredicateWithSubpredicates:@[yearPredicate,monthPredicate,dayPredicate,notDonePredicate,notDeletedPredicate]];

    [fetchRequest setPredicate:busqueda];
  NSFetchedResultsController *aFetchedResultsController =
              [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                  managedObjectContext:managedObjectContext
                                                    sectionNameKeyPath:nil cacheName:nil];
  aFetchedResultsController.delegate = self;
  [self setFetchedResultsController:aFetchedResultsController];


  [aFetchedResultsController release];
  [fetchRequest release];
  [sortDescriptor release];
  [sortDescriptors release];


  return fetchedResultsController;
    

【问题讨论】:

【参考方案1】:

好的,我对核心数据一无所知,但从我在过去两分钟内的研究来看,您似乎没有遍历 NSManagedObjectContext 的对象。您需要在上下文中创建搜索并从中获取结果。然后遍历结果并随意修改。

这是取自this answer的示例:

NSManagedObjectContext * context = [self managedObjectContext];
NSFetchRequest * fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:[NSEntityDescription entityForName:@"ShoppingBasket" inManagedObjectContext:context]];
NSArray * result = [context executeFetchRequest:fetch error:nil];
for (id basket in result)
    [context deleteObject:basket];

所以获取上下文,创建一个搜索,根据搜索条件从上下文中获取一个数组,循环遍历结果并按照您的意愿更新它们。

【讨论】:

大概他已经使用 fetchedResultsController 进行了一次抓取,因此没有必要再进行一次抓取。请参阅我的回答以使用现有的 fetchedResultsController 结果集。 我同意重复提取是相当愚蠢和浪费时间的。感谢您提供的信息,如果我了解核心数据,它将派上用场。【参考方案2】:

如果您已经使用 fetchedResultsController 来填充 tableView,那么您可以像这样遍历 fetchedResultsController 中的对象:

- (IBAction)allDoneAction:(id)sender 

    NSArray *objects = [fetchedResultsController fetchedObjects];

    for (NSManagedObject *mo in objects) 
       [mo setValue:@"Done" forKey:@"isDone"];i++;
    

    NSError *error;
    bool result = [[fetchedResultsController managedObjectContext] save:&error];

    if (!result) 
       NSLog(@" error saving context, %@, %@", error, error.userInfo);
    


顺便说一句,您应该检查保存调用中的错误,因此不要传入 nil。

【讨论】:

是的,我正在使用 fetchedResultsController 填充 tableView。您的建议,添加 int i=0;在“fetchResults”处显示警告并在执行时显示异常:由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[NSFetchedResultsController fetchedResults]:无法识别的选择器已发送到实例 发布您用于创建 fetchedResultsController 的代码 不,别打扰我弄错了fetchedObjects而不是fetchedResults,请查看更正后的代码。

以上是关于核心数据对象循环更新的主要内容,如果未能解决你的问题,请参考以下文章

在核心数据线程安全中同时枚举托管对象

Swift 中的核心数据:仅在 for 循环中保存最后一个对象

快速更新核心数据对象 3

循环访问核心数据对象数组时随机访问日期类型属性失败

如何更新核心数据中的对象?

快速更新核心数据上的对象 4