2011-07-19 7 views
3

私たちのUITableViewは、特定のセクションの行数を返します。私たちが経験していることは、cellForRowAtIndexPathが呼び出されるころまでに番号が変更され、配列インデックスが範囲外になることになります。numberOfRowsInSectionとcellForRowAtIndexPathを同期させるにはどうすればよいですか?

これらの2つの方法を同期する良い方法はありますか。そのため、基礎となるデータは変更されません。 @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

自分で解決したように、スコープがメソッドを超えているため、@ synchronizedを使用することはできません。

LockオブジェクトをnumberOfRowsInSectionでロックし、そのロックを解除して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を更新しようとしたことがあり:何をする必要があなたはどのあなたがcellForRowAtIndexPathにする必要があり、例えば渡された行は、もはや有効ではないかもしれないという事実を扱うロックないことを確実にあります)メインスレッドのみ?これにより、getNumberOfRowsおよびconfigureCellAtの呼び出しによるインターリーブからモデルへの更新の可能性が低減されます。この例では、ランダムスレッドでモデルを更新してから、メインスレッドでデータを再読み込みしています。あなたがモデルであることをスレッドセーフ(またはメインスレッドのみで更新/読み込み)することをお勧めします。

+0

これは私たちが目指していたアプローチと同じです。しかし、ユーザー数は0になる可能性があります。インターフェイスに違反するため、ここでは無限のセルを返すことはできません。助言がありますか? – tjg184

+0

少し質問を更新しました。 [[self invokeOnMainThreadAndWaitUntilDone:NO] refresh:self]を使用しています。テーブルを更新します。 – tjg184

+0

refresh:セルフ・コール[self.tableView reloadData] – tjg184

2

脳はすでに答えていますが、私は "メインスレッドのモデルを更新する"という事例コードを強調したいと思います。

一部のバックグラウンドスレッドでモデルが変更されたため、この問題が発生する可能性があります。タイムラインは次のようになります

{NSThread番号= 1、名前=メイン} - [のViewControllerのtableView:numberOfRowsInSection:]

{NSThread数= 8、名前=(NULL)(例えば、10を返します) } [ViewController tableView:cellForRowAtIndexPath:](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 
    }); 
}); 

希望があなたを助けてくれることを願っています。 :)

関連する問題