我们如何将numberOfRowsInSection同步到cellForRowAtIndexPath?

时间:2011-07-19 15:15:00

标签: iphone uitableview synchronization

我们的UITableView返回给定部分的行数。我们所遇到的是,当调用cellForRowAtIndexPath时,数字已经改变,所以我们最终得到数组索引超出界限。

是否有一种同步这两种方法的好方法,因此底层数据不会改变?我们考虑使用@synchronized,但不确定何时释放锁。

我们正在做的另一件事是刷新表,这是来自一个单独的线程。

[self addUsers:usersToShow];       
[[self invokeOnMainThreadAndWaitUntilDone:NO] refresh:self]; // is this the issue?


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.users.count;  // returns 10 for example
}

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

    UITableViewCell *newCell= nil;

    static NSString *cellId = @"cellId";

    cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"MyCell" owner:self options:nil];
        cell = newCell;
        self.newCell = nil;
    }

    User* user = [self.users objectAtIndex:indexPath.row]; // index out of bounds now because number of users has changed
}

2 个答案:

答案 0 :(得分:2)

由于您已经为自己解决了问题,因此无法使用@synchronized,因为范围超出了方法范围。

您不希望尝试使用Lock对象,将其锁定在numberOfRowsInSection中并将其解锁为cellForRowAtIndexPath。它不会起作用。你需要做的是确保你在cellForRowAtIndexPath中做你需要的任何锁定,并处理传入的行可能不再有效的事实,例如:

User * user = nil;    
@synchronized(self.users) {
        if (indexPath.row < [self.users count]) {
             user = [self.users objectAtIndex:indexPath.row];
        }

}

if (user) {
    //configure cell
}
else {
    //set cell fields to be blank
}

您是否尝试仅在主线程中更新模型(self.users)?这应该减少对模型更新的可能性,因为它与对getNumberOfRows和configureCellAt的调用交错。在您给出的示例中,您正在随机线程上更新模型,然后在主线程上重新加载数据。我建议确保你的模型是线程安全的(或仅在主线程中更新/读取)。

答案 1 :(得分:2)

尽管大脑已经回答了,但我想用示例代码强调“主线程中的更新模型”。

您可能会遇到此问题,因为您的模型在某些后台线程中已更改。时间表应如下所示:

{NSThread number = 1,name = main} - [ViewController tableView:numberOfRowsInSection:](例如返回10)

{NSThread number = 8,name =(null)} - [ViewController changeTheModel](从模型中删除一些对象,或获取少于10个对象的新模型)

{NSThread number = 1,name = main} - [ViewController tableView:cellForRowAtIndexPath:](索引超出绑定异常,因为第10个对象不存在)

要解决此问题,您应该在更改模型时执行以下操作:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSArray* items = [self getNewModel];// get new model on background thread
    dispatch_async(dispatch_get_main_queue(), ^ {
        self.items = items;// replace the model with new one on main thread
        [self.tableView reloadData];// refresh table without index out of bound exception
    });
});

希望这可以帮到你。 :)