[英]How To Pass Dynamic row and Section Array to numberOfRowsInSection and 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.