托管对象上下文在保存期间崩溃

时间:2014-05-21 14:36:09

标签: ios core-data nsfetchedresultscontroller

我的应用程序调用核心数据并使用nsfetchedresultscontroller管理对象,并使用结果构建tableview。点击时的tableview单元格推送到详细视图,我可以在其中更改对象的属性并保存。

- (void)viewDidLoad {
  [super viewDidLoad];
  NSError *error;
  if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"Failed to fetch data");
  }
}

- (NSFetchedResultsController *)fetchedResultsController {
  if (_fetchedResultsController) {
    return _fetchedResultsController;
  }
  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
  fetchRequest.entity = [NSEntityDescription entityForName:@"ZTExercise" inManagedObjectContext:[[ZTDataManager sharedDataManager] mainContext]];
  fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];

  _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[ZTDataManager sharedDataManager].mainContext sectionNameKeyPath:@"sectionTitle" cacheName:nil];
  _fetchedResultsController.delegate = self;

  return _fetchedResultsController;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  if ([segue.identifier isEqualToString:@"detailExerciseSegue"]) {
    ZTExerciseDetailController *controller = segue.destinationViewController;
    NSIndexPath *selectedIndexPath;
    ZTExercise *exercise;
    if (self.searchDisplayController.isActive) {
      selectedIndexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
      exercise = self.searchResults.allValues[selectedIndexPath.section][selectedIndexPath.row];
    } else {
      selectedIndexPath = [self.tableView indexPathForSelectedRow];
      exercise = [self.fetchedResultsController objectAtIndexPath:selectedIndexPath];
    }
    controller.exercise = exercise;
  }
}

在tableview控制器中,还有一个搜索栏,在点击单元格时会将对象推到同一个视图。

触发崩溃的操作是

[self applyCustomizationToAlertView:[ZTAlertView showAlertWithTitle:@"Add record" message:@"Enter new lifting weight (lbs)" cancelTitle:@"Cancel" otherTitle:@"Add" contentView:addRecordView completion:^(BOOL cancelled, NSInteger buttonIndex) {
    if (cancelled) {
      return;
    }
    if (buttonIndex == 1) {
      if (addRecordTextField.text && [addRecordTextField.text length]) {

        ZTExerciseRecord *newRecord = [ZTExerciseRecord insertObjectInContext:[ZTDataManager sharedDataManager].mainContext];
        newRecord.score = [addRecordTextField.text integerValue];
        [self.exercise insertObject:newRecord inERecordsAtIndex:0];

        NSError *error;
        if (![[ZTDataManager sharedDataManager].mainContext save:&error]) {
          NSLog(@"Failed to save data");
          return;
        }
        [self.tableView beginUpdates];
        [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:[self.sections indexOfObject:ZTSectionNameLift]]] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];
        return;
      }
    }
  }]];

self.exercise.eRecords = [NSOrderedSet orderedSetWithArray:[self.exercise.eRecords sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"dateCreated" ascending:NO]]]];

当我通过搜索栏搜索对象时,如果点击的单元格不是searchtableview的第一个条目,则会发生崩溃。它推送到详细视图,但是当我执行涉及更改关系或保存上下文的操作时,它会使用此代码崩溃

CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  *** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0] with userInfo (null)
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

感谢所有帮助, 提前谢谢。

更新1 错误说我在索引1处插入了一些内容,但在我的所有代码中,访问0以外索引的唯一部分是在表viewdata源中,这与获取的对象数一致。

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  if (self.recordTableView == tableView) {
    return 1;
  }
  return 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  if (self.recordTableView == tableView) {
    return [self.exercise.eRecords count];
  }
  return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  NSString *cellIdentifier;
  UITableViewCell *cell;
  if (self.recordTableView == tableView) {
    cellIdentifier = @"ZTExerciseLogCell";
    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
      cell = [[ZTExerciseLogCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
  }
  [self configureCell:cell atIndexPath:indexPath];
  return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
  if ([cell.reuseIdentifier isEqualToString:@"ZTExerciseLogCell"]) {
    ZTExerciseLogCell *newCell = (ZTExerciseLogCell *)cell;
    newCell.record = self.exercise.eRecords[indexPath.row];
  }
}

ZTExerciseController - >推 - > ZTExerciseDetailController

我注意到的另一件事是在名为ZTExerciseDetailController的类中发生错误但在崩溃日志中错误表明它发生在ZTExerciseController

此崩溃日志属于在练习的mutableorderedset中插入对象

*** First throw call stack:
(
    0   CoreFoundation                      0x0000000101cc3495 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001017c399e objc_exception_throw + 43
    2   CoreFoundation                      0x0000000101c7be3f -[__NSArrayI objectAtIndex:] + 175
    3   ZetaProject                         0x0000000100004524 -[ZTExerciseController configureCell:atIndexPath:] + 404
    4   ZetaProject                         0x0000000100005a13 -[ZTExerciseController controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:] + 819
    5   CoreData                            0x0000000102047c3b -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 4187
    6   CoreFoundation                      0x0000000101d18d9c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    7   CoreFoundation                      0x0000000101c7b51d _CFXNotificationPost + 2381
    8   Foundation                          0x00000001001547fa -[NSNotificationCenter postNotificationName:object:userInfo:] + 68
    9   CoreData                            0x0000000101f7348a -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 74
    10  CoreData                            0x0000000101ff9c8b -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 331
    11  CoreData                            0x0000000101f6f243 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 1875
    12  CoreData                            0x0000000101ff9d25 __90-[NSManagedObjectContext(_NSInternalNotificationHandling) _processEndOfEventNotification:]_block_invoke + 85
    13  CoreData                            0x0000000101f90c7b developerSubmittedBlockToNSManagedObjectContextPerform + 107
    14  CoreData                            0x0000000101f90bc4 -[NSManagedObjectContext performBlockAndWait:] + 132
    15  CoreData                            0x0000000101f9364b -[NSManagedObjectContext(_NSInternalNotificationHandling) _processEndOfEventNotification:] + 123
    16  CoreFoundation                      0x0000000101d18d9c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    17  CoreFoundation                      0x0000000101c7b51d _CFXNotificationPost + 2381
    18  Foundation                          0x00000001001547fa -[NSNotificationCenter postNotificationName:object:userInfo:] + 68
    19  Foundation                          0x0000000100149460 -[NSUndoManager _postCheckpointNotification] + 92
    20  Foundation                          0x0000000100149242 -[NSUndoManager _endUndoGroupRemovingIfEmpty:] + 95
    21  Foundation                          0x00000001001985ff __NSFirePerformWithOrder + 339
    22  CoreFoundation                      0x0000000101c8edc7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    23  CoreFoundation                      0x0000000101c8ed37 __CFRunLoopDoObservers + 391
    24  CoreFoundation                      0x0000000101c6e438 __CFRunLoopRun + 712
    25  CoreFoundation                      0x0000000101c6dd83 CFRunLoopRunSpecific + 467
    26  GraphicsServices                    0x0000000103471f04 GSEventRunModal + 161
    27  UIKit                               0x000000010059fe33 UIApplicationMain + 1010
    28  ZetaProject                         0x000000010002a6a3 main + 115
    29  libdyld.dylib                       0x00000001030f35fd start + 1
)

更新2

好的,我认为已经解决了这个问题。当对运动对象进行更改时,它显然会调用NSFetchedResultsControllerDelegate(Update type)函数:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
  switch(type) {
    case NSFetchedResultsChangeInsert:
      [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;

    case NSFetchedResultsChangeDelete:
      [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;

    case NSFetchedResultsChangeUpdate:
      [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
      break;

    case NSFetchedResultsChangeMove:
      [self.tableView deleteRowsAtIndexPaths:[NSArray
                                              arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      [self.tableView insertRowsAtIndexPaths:[NSArray
                                              arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
  }
}

然后它调用configureCell:atIndexPath:function:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
  ZTExerciseCell *newCell = (ZTExerciseCell *)cell;
  ZTExercise *exercise;
  if (self.searchDisplayController.isActive && [self.searchResults count]) {
    exercise = self.searchResults.allValues[indexPath.section][indexPath.row];
  } else {
    exercise = [self.fetchedResultsController objectAtIndexPath:indexPath];
  }
  newCell.exercise = exercise;
}

但问题是在此期间搜索表视图处于活动状态并获取错误的对象。如何验证何时来自委托获取结果函数或tableviewcell函数?还是有更好的方法来使用nsfetchresultscontroller操作搜索表视图?

2 个答案:

答案 0 :(得分:0)

第二行日志表示您正在尝试访问不存在的数组索引。也许您忘记初始化它或其他东西。 检查XCode 5: How to Debug? Get the line of the error? NSInvalidArgumentException并跟踪代码崩溃的哪一行

答案 1 :(得分:0)

NSFetchedResultsController * consultMessageFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[[[WYCoreDataStorage shareStore] coreDataHelper] mainContext] sectionNameKeyPath:nil cacheName:entityName];

cacheName:entityName 这个设置了cache,导致的,如果设置了,一定要不用的时候移除掉

苹果文档如下:: 重要 如果使用缓存,则必须在更改任何获取请求,其谓词或其排序描述符之前调用deleteCacheWithName :.除非将cacheName设置为nil,否则不得为多个查询重用相同的获取结果控制器。