![](/img/trans.png)
[英]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.