簡體   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