0

状況:

配列からデータを取得するテーブルビューを持つビューコントローラーがあります。その配列のデータの読み込みが非常に遅いため、要素をオンデマンドで読み込みます (tableView:cellForRowAtIndexPath: でトリガーされます)。

問題:

最初に (つまり、ビューが読み込まれた後)、表示されているセル (最初の 6 つ) のみを読み込みます。しかし、スクロールしようとすると、他のすべての人が一度にロードされます! (ロード中のブレークポイントでテストされ、明らかに [UITableView _createPreparedCellForGlobalRow:withIndexPath:] が行ごとに呼び出されます)

コード:

PlayerListDataModel.m

@implementation PlayerListDataModel
(...)
-(NSString *)nombre {
    if (!self.loaded) [self load];
    return _nombre;
}
-(void)load {
    NSLog(@"Loading %d", self.sqlId);
    [OMNIGAME loadListCell:self];
    self.loaded = YES;
}
@end

PlayerListViewController.m

@implementation PlayerListViewController

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; }

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.jugadores.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* cellId = @"PlayerListCell";
    PlayerListCell* cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (!cell) {
        cell = [[PlayerListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
    }
    PlayerListDataModel* data =[self.jugadores objectAtIndex:indexPath.row];
    cell.dem = data.bestDem;
    cell.nombre = data.nombre;
    cell.apellido = data.apellido;
    cell.escudo = data.escudo;
    cell.equipo = data.equipo;
    cell.age = data.edad;
    cell.bandera = data.bandera;
    cell.price = data.price;
    cell.energia = data.energy;
    cell.valor = data.valor;

    return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return tableView.bounds.size.height/7;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return tableView.bounds.size.height/7;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (!self.search) {
        self.search = [[PlayerSearchView alloc] init];
        self.search.search.delegate = self;
    }
    return self.search;
}

質問:

これは意図した動作ですか? もしそうなら、それをハックする方法はありますか?そうでない場合、私が間違っていることは何ですか?

4

3 に答える 3

1

これは予期しない、実際には意図しない動作です。カスタムセルの実装はわかりませんが、これがそのような動作につながる可能性があるとは想像できませんでした. 私の意見では、 -tableView:cellForRowAtIndexPath: 自体の実装に問題はありません。

私の疑いは、(i) スクロールを開始している間にテーブルビューの境界が何らかの形で変化するか、(ii) Mac にインストールされているツールがシミュレーターに干渉することです。したがって、私の提案は次のとおりです。

(i) Dhruv Goel が提案するように、行の高さをハードコーディングしてみてください。テーブルビューの境界を縮小する必要がある場合、これにより複雑さが生じる可能性があります (行の高さが低いほど、より多くの行をキューに入れる必要があります)。しかし、これが起こるべき適切な理由を想像することはできません。

(ii) シミュレータのみを介してアプリをデバッグしますか? その場合は、このリンクを確認してください: UITableViewCell cellForRowAtIndexPath calling large number of rows when first scrolling . ウィンドウ管理用のツールのようなツールがシミュレーターに干渉する可能性があります。

最後の点は、私を別の質問に導きます。この問題が UITableViewController の他のサブクラス (この特定のプロジェクト) でも発生するかどうかを確認しましたか?

于 2013-06-18T22:40:49.590 に答える
0

はい、これは意図した動作です。実際、これは UITableView の主要な機能の 1 つです。現在ビューに表示する必要があるセルをメモリに保持するだけです。スクロールすると、テーブル ビューは古いセルを 1 つずつキューから取り出し、新しいデータで再利用します。したがって、最初に 5 つまたは 6 つのセルが表示されている場合、スクロールすると新しいセルが必要になります。

PlayerListCell* cell = [tableView dequeueReusableCellWithIdentifier:cellId];

可能な場合はセルを再利用しようとします。そうでない場合は、新しいセルが次のように作成されます。

if (!cell) {
cell = [[PlayerListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}

これを回避する方法は、セルをデキューせず、毎回新しいセルを作成 (初期化の割り当て) することですが、これはお勧めできません。

于 2013-06-18T20:28:59.347 に答える
0

これはバグではなく、文書化されています。

デリゲート メソッド:

tableView:heightForHeaderInSection:

画面上にあるセルに関係なく、テーブルビュー内のすべてのセルに対して呼び出されます。

ドキュメントの議論が言うように:

討論

このメソッドにより、デリゲートはさまざまな高さの行を指定できます。このメソッドが実装されている場合、返される値は、指定された行の UITableView の rowHeight プロパティに指定された値をオーバーライドします。

rowHeight プロパティの代わりに tableView:heightForRowAtIndexPath: を使用すると、パフォーマンスに影響があります。テーブル ビューが表示されるたびに、その行ごとにデリゲートで tableView:heightForRowAtIndexPath: が呼び出されます。これにより、多数の行 (約 1000 以上) を持つテーブル ビューで重大なパフォーマンスの問題が発生する可能性があります。

于 2013-08-28T15:18:26.923 に答える