NSFetchedResultsController的NSFetchedResultsChangeUpdate事件中的NSRangeException异常 [英] NSRangeException exception in NSFetchedResultsChangeUpdate event of NSFetchedResultsController

查看:151
本文介绍了NSFetchedResultsController的NSFetchedResultsChangeUpdate事件中的NSRangeException异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 UITableView 使用 NSFetchedResultsController 作为数据源。



核心数据存储在并行运行的多个后台线程中更新(每个线程使用自己的 NSManagedObjectContext )。



主线程观察 NSManagedObjectContextDidSaveNotification
通知并更新其上下文 mergeChangesFromContextDidSaveNotification:



有时会发生 NSFetchedResultsController 发送
NSFetchedResultsChangeUpdate

例如:获取结果控制器的结果集包含
b $ b 1节带4个对象。第一个对象在一个线程中被删除。
最后一个对象在不同的​​线程中更新。然后有时
会发生:




  • controllerWillChangeContent:


  • 控制器:didChangeObject:atIndexPath:forChangeType:newIndexPath:使用$调用$ this; $调用$; $调用
    type = NSFetchedResultsChangeDelete,indexPath.row = b $ b type = NSFetchedResultsChangeUpdate,indexPath.row = 3。



但是获取的结果控制器现在只包含3个对象,

  MyManagedObject * obj = [controller objectAtIndexPath:indexPath] 

根据 NSFetchedResultsChangeUpdate
事件更新表视图单元格时,会与<$ c $感谢您的任何帮助或想法!

>解决方案

我现在找到了我的问题的解决方案。在更新事件的情况下,不需要调用

  [self.controller objectAtIndexPath:indexPath] 
因为更新的对象已作为 参数提供给,所以



< >



因此,我替换了 -configureCell:atIndexPath:通过直接使用更新的对象的 -configureCell:withObject:方法。这似乎工作没有问题。



代码看起来像这样:

   - (void)configureCell:(UITableViewCell *)cell withObject:(MyManagedObject *)myObj 
{
cell.textLabel.text = myObj.name;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@ MyCellIdentifier];
[self configureCell:cell withObject:[self.controller objectAtIndexPath:indexPath]];
return cell;
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type newIndexPath: NSIndexPath *)newIndexPath
{
UITableView * tableView = self.tableView;

switch(type){
/ * ... * /
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] withObject:anObject];
break;
/ * ... * /
}
}


I have a UITableView that uses an NSFetchedResultsController as data source.

The core data store is updated in multiple background threads running in parallel (each thread using it's own NSManagedObjectContext).

The main thread observes the NSManagedObjectContextDidSaveNotification notification and updates it's context with mergeChangesFromContextDidSaveNotification:.

Sometimes it happens that the NSFetchedResultsController sends an NSFetchedResultsChangeUpdate event with an indexPath that does not exist anymore at that point.

For example: The result set of the fetched results controller contains 1 section with 4 objects. The first object is deleted in one thread. The last object is updated in a different thread. Then sometimes the following happens:

  • controllerWillChangeContent: is called.
  • controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: is called with type = NSFetchedResultsChangeDelete, indexPath.row = 0.
  • controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: is called with type = NSFetchedResultsChangeUpdate, indexPath.row = 3.

But the fetched results controller contains only 3 objects now, and if call

MyManagedObject *obj = [controller objectAtIndexPath:indexPath]

to update the table view cell according to the NSFetchedResultsChangeUpdate event, this crashes with a NSRangeException exception.

Thank you for any help or ideas!

解决方案

I have now found a solution for my problem. In the case of an update event, there is no need to call

[self.controller objectAtIndexPath:indexPath]

because the updated object is already supplied as the anObject parameter to the -controller:didChangedObject:... delegate.

I have therefore replaced -configureCell:atIndexPath: by a -configureCell:withObject: method that uses the updated object directly. This seems to work without problems.

The code looks now like this:

- (void)configureCell:(UITableViewCell *)cell withObject:(MyManagedObject *)myObj
{
    cell.textLabel.text = myObj.name;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCellIdentifier"];
    [self configureCell:cell withObject:[self.controller objectAtIndexPath:indexPath]];
    return cell;
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;

    switch(type) {
    /* ... */           
    case NSFetchedResultsChangeUpdate:
        [self configureCell:[tableView cellForRowAtIndexPath:indexPath] withObject:anObject];
        break;
    /* ... */           
    }
}

这篇关于NSFetchedResultsController的NSFetchedResultsChangeUpdate事件中的NSRangeException异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆