繁体   English   中英

我们如何将 numberOfRowsInSection 同步到 cellForRowAtIndexPath?

[英]How do we sync numberOfRowsInSection to cellForRowAtIndexPath?

我们的 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
}

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

您可能会遇到问题,因为您的 model 在某些后台线程中发生了更改。 时间线应如下所示:

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

{NSThread number = 8, name = (null)} -[ViewController changeTheModel](从model中移除一些对象,或者得到一个少于10个对象的新model)

{NSThread number = 1, name = main} -[ViewController tableView:cellForRowAtIndexPath:] (获取索引越界异常,因为第 10 个 object 不存在)

为了解决这个问题,当你改变你的 model 时,你应该这样做:

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
    });
});

希望这可以帮助你。 :)

正如您自己制定的那样,您不能使用@synchronized,因为 scope 超出了该方法。

您不想尝试使用 Lock object,将其锁定在 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
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM