使用Core Data Asynchronous UISearchDisplayController时出现NSRangeException

时间:2011-06-11 01:01:20

标签: objective-c ios core-data uisearchdisplaycontroller

我正在异步获取数据,我将其用作指南:http://deeperdesign.wordpress.com/2011/05/30/cancellable-asynchronous-searching-with-uisearchdisplaycontroller/

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{    
//setup request / predicate etc...            
[self.searchQueue addOperationWithBlock:^{
             NSError *error;             
             self.matchingObjects = [self.managedObjectContext executeFetchRequest:request error:&error];
             [request release];

             [[NSOperationQueue mainQueue] addOperationWithBlock:^
              {
                  [self.searchDisplayController.searchResultsTableView reloadData];
              }];

     }];            
    // Return YES to cause the search result table view to be reloaded.
    return NO;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    
        // Return the number of rows in the section.
        return [self.matchingObjects count];
}

每隔一段时间我就会得到一些效果:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSArray objectAtIndex:]: index 0 beyond bounds for empty array'

当访问它以在以下位置构造表格单元格时,会在matchingObjects ivar处抛出此内容:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

崩溃不会一直发生,似乎只是偶然发生。我猜测,matchObjects数组上的count正在返回某个值,该值会更改并且不会更新。

我不完全确定如何处理这个问题 - 几个小时以来一直在研究这个问题,有什么我想念的吗?

1 个答案:

答案 0 :(得分:1)

我想出它是什么 - 花了我一段时间,但我再次看了一下我刚刚联系的例子。我正在后台线程中更新self.matchingObjects iVar,这在某些情况下导致主线程中可用的数组范围与后台线程不匹配。因此,例如,变量可能已在后台线程中更新,并且主线程可能仍在访问变量中已不再存在的范围的一部分。

通过修改我的代码来修复它:

 [self.searchQueue addOperationWithBlock:^
 {
    NSError *error;

    NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
    [request release];

    [[NSOperationQueue mainQueue] addOperationWithBlock:^
    {
       self.matchingObjects = results;
       [self.searchDisplayController.searchResultsTableView reloadData];
    }];

}];

现在搜索结果被加载到名为“results”的临时保存数组中,并且matchObjects iVar首先在主线程中更新,然后重新加载tableView。这样,tableView总是引用一个在访问时从不更改的数组,因为tableView依赖于matchesObjects来获取行数和数据。