2013-10-10 44 views
1

我無法弄清楚這一點,但是我從NSFetchedResultsController刪除一個對象時似乎有一個空indexPath。null刪除對象時的indexPaths

當我刪除我的目標,我這樣做:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 
    if (editingStyle == UITableViewCellEditingStyleDelete) { 
     // Delete the object 
     NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; 
     [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]]; 

     [self saveContext]; 
    } 
} 

設置NSFetchedResultsController

- (NSFetchedResultsController *)fetchedResultsController { 
    if (_fetchedResultsController != nil) { 
     return _fetchedResultsController; 
    } 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    [fetchRequest setFetchBatchSize:20]; 

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Route" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    NSSortDescriptor *nameSort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]; 
    NSArray *sortDescriptors = @[nameSort]; 
    [fetchRequest setSortDescriptors:sortDescriptors]; 

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Routes"]; 
    self.fetchedResultsController = aFetchedResultsController; 
    self.fetchedResultsController.delegate = self; 

    NSError *error = nil; 
    if (![self.fetchedResultsController performFetch:&error]) { 
     NSLog(@"Unresolved error with NSFetchedResultsController: %@", [error description]); 
     abort(); 
    } 

    return _fetchedResultsController; 
} 

這是在失敗發生:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 

    switch (type) { 
      // Data was inserted - insert the data into the table view 
     case NSFetchedResultsChangeInsert: { 
      [self.savedRoutesTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 

      break; 
     } 
      // Data was deleted - delete the data from the table view 
     case NSFetchedResultsChangeDelete: { 
      [self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      break; 
     } 
     case NSFetchedResultsChangeUpdate: { 
      SavedRoutesTableViewCell *cell = (SavedRoutesTableViewCell *)[self.savedRoutesTableView cellForRowAtIndexPath:indexPath]; 
      [cell configureCellWithRoute:[controller objectAtIndexPath:newIndexPath]]; 
      break; 
     } 
     case NSFetchedResultsChangeMove: { 
      [self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      [self.savedRoutesTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
      break; 
     } 
     default: 
      break; 
    } 
} 

在didChangeObject方法,我的indexPath和newIndexPath都是零。我可以NSLog我的對象,我看到實體。它崩潰的[self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];方法不同之處:

CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0] with userInfo (null) 

當我保存這個對象,我保存它是這樣的:

self.route.name = routeName; 
NSManagedObjectContext *tempContext = [self.route managedObjectContext]; 

[tempContext performBlock:^{ 
     NSError *error = nil; 
     if (![tempContext save:&error]) { 
      NSLog(@"an error occurred: %@", [error localizedDescription]); 
     } 

     [self.managedObjectContext performBlock:^{ 
      NSError *error = nil; 
      if (![_managedObjectContext save:&error]) { 
       NSLog(@"error in main context: %@", [error localizedDescription]); 
      } 
     }]; 
    }]; 

我真的不知道還有什麼地方調試這個自NSFetchedResultsController只是沒有給我返回刪除對象的indexPath。有什麼想法嗎?提前致謝。

編輯: 嗯,我找到了導致錯誤的罪魁禍首,但我不知道它爲什麼。基本上我有一個ViewController,如果它正在編輯路徑,它將接收來自主要MOC的Route實體,或者如果您正在創建新路線,它將插入一個新實體。所以在那個viewController中,如果我正在編輯一個路由,因爲我想爲它的父母使用兩個MOC,一個temp和一個main,所以如果用戶決定取消而不是創建一個新路由,我需要將該路線轉移到另一個環境,以使其他代碼可以工作。所以說,「轉讓」的模樣:

NSManagedObjectContext *moc = _route.managedObjectContext; 
    NSManagedObjectID *routeId = [_route objectID]; 
    self.tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    self.tempContext.parentContext = moc; 
    NSManagedObject *localRoute = [self.tempContext objectWithID:routeId]; 
    self.route = localRoute; 

有了這個代碼,我添加上的位置,以現有路由的工作原理現在的位置是在同一個環境中,但不知何故,它攪亂了從主刪除現有路由MOC。不知道爲什麼和什麼是最好的解決方案。

+0

既然你已經想通了,爲什麼不發表您的解決方案作爲一個答案,而不是把它置於問題中?稍後他人會更容易找到。 – Makoto

回答

0
NSManagedObjectContext *moc = _route.managedObjectContext; 
NSManagedObjectID *routeId = [_route objectID]; 
self.tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
self.tempContext.parentContext = moc; 
NSManagedObject *localRoute = [self.tempContext objectWithID:routeId]; 
self.route = localRoute; 

必須得到與路線相關的上下文。

+0

你應該添加一些上下文來解釋和標記這個答案被接受。 – Kamchatka

0

有相同的問題,並通過確保NSFetchedResultsController總是使用相同的NSManagedContext來解決它。例如,如果你使用fetch控制器從數據庫中獲取對象,並且稍後想要刪除該對象,請確保fetch控制器使用它在獲取期間使用的託管上下文。

NSFetchedResultsController針對使用UITableView進行了優化,UITableView是用戶界面組件,並且用戶界面應始終由主線程處理,因此每次進入獲取時都不需要創建新的NSManagedContext ...因此,實現此代碼應該可以解決此問題:

@synthesize fetchedResultsController = __fetchedResultsController; @synthesize managedObjectContext = __managedObjectContext;

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (__managedObjectContext != nil) 
    { 
     return __managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = ap.persistentStoreCoordinator; 
    if (coordinator != nil) 
    { 
     __managedObjectContext = [[NSManagedObjectContext alloc] init]; 
     [__managedObjectContext setPersistentStoreCoordinator:coordinator]; 
    } 
    return __managedObjectContext; 
} 

ap爲指針的AppDelegate:

ap = [[UIApplication sharedApplication] delegate]; 

這段代碼的作用是創建MOC的一個實例,之後再利用它。警告:這是不是線程安全的,並且它不必須是(因爲你應該只有主線程使用它),所以如果你missuse它也不會工作...

使用:

- (NSFetchedResultsController *)fetchedResultsController 
{ 
    if (__fetchedResultsController != nil) 
    { 
     return __fetchedResultsController; 
    } 
    //create __fetchedResultsController 
    // do some fetching 
    return __fetchedResultsController; 
} 

所以,當你想填充表:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return [[self.fetchedResultsController sections] count]; 
} 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return [__fetchedResultsController.fetchedObjects count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 

    NSManagedObject *managedObject = [__fetchedResultsController objectAtIndexPath:indexPath]; 

    cell.textLabel.text = [managedObject valueForKey:@"smth."]; 

    return cell; 
} 

如果數據集只是改變:

__fetchedResultsController = nil; 
[tableView reloadData] 

而且everyt興包括NSFetchedResultsControllers delegat方法將正常工作,沒有零indexPaths等等...

希望我幫助別人......