私は、Webから取得したデータを含むかなり大きなUITableViewを備えたiPhoneアプリで作業しているので、作成と使用を最適化しようとしています。
dequeueReusableCellWithIdentifier
は非常に便利であることがわかりましたが、これを使用して多くのソースコードを見た後、この関数を使用するのが良いかどうか疑問に思っています。
人々が通常行うことは次のとおりです。
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];
// Add elements to the cell
return cell;
そして、これが私がやった方法です:
// The cell row
NSString identifier = [NSString stringWithFormat:@"Cell %d", indexPath.row];
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell != nil)
return cell;
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier];
// Add elements to the cell
return cell;
違いは、人々がすべてのセルに同じ識別子を使用するため、キューからの削除は新しいセルの割り当てのみを回避することです。
私にとって、キューイングのポイントは各セルに一意の識別子を与えることでした。したがって、アプリが既に表示されているセルを要求する場合、割り当ても要素の追加も必要ありません。
罰金で どちらが最適かはわかりませんが、「一般的な」方法では、テーブルのメモリ使用量が表示されるセルの正確な数に制限されます。 (キューに内部制限がない限り)。
このように使用するのは間違っていますか?または、開発者のニーズに応じて、開発者次第ですか?
dequeueReusableCellWithIdentifier
の目的は、使用するメモリを減らすことです。画面が4つまたは5つのテーブルセルに収まる場合、再利用を行うと、テーブルに1000エントリがある場合でも、メモリに4つまたは5つのテーブルセルを割り当てるだけで済みます。
2番目の方法では、再利用はありません。 2番目の方法には、テーブルセルの配列を使用するだけの利点はありません。テーブルに1000個のエントリがある場合、メモリに1000個のセルが割り当てられます。それを行おうとする場合は、それらを配列に入れ、行番号で配列にインデックスを付けてセルを返します。固定セルを持つ小さなテーブルは合理的な解決策かもしれませんが、動的なテーブルや大きなテーブルには良い考えではありません。
セル識別子について-識別子に「セル」を使用する代わりに、OPのような一意の識別子を使用する代わりに、「タイプ識別子」を使用できますか?たとえば、テーブルに3種類のセルがあり、1つに非常に複雑なサブレイアウトがあり、1つにStyle1
、およびStyle2
、これら3つをすべて個別に識別し、dequeueがnil
になったら再構築する必要があります。
例えば:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
NSString* ident = @"";
if(indexPath.section == 0) ident= @"complicated";
if(indexPath.section == 1) ident= @"style1";
if(indexPath.section == 2) ident = @"style2";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:ident];
if(cell == nil){
if(ident == @"complicated"){
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:ident] autorelease];
// do excessive subview building
}
if(ident == @"style1"){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle1 reuseIdentifier:ident] autorelease];
}
if(ident == @"style2"){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyle2 reuseIdentifier:ident] autorelease];
}
}
if(ident == @"complicated"){
// change the text/etc (unique values) of our many subviews
}
if(ident == @"style1"){
[[cell textLabel] setText:@"Whatever"];
}
if(ident == @"style2"){
[[cell textLabel] setText:@"Whateverelse"];
}
return cell;
}
(私がここに書いたので、おそらくこのコードは実行されませんが、うまくいけばあなたはそのアイデアを得ます。)
Appleは、すべての識別子を"cell"
、あなたは思いませんか?
慣用的な方法(最初に説明した方法)が最適に機能する理由を理解するのに役立つドキュメントは、 ITableViewCellクラスリファレンスinitWithStyle:reuseIdentifier:
メソッドのセクションです。
reuseIdentifier
サブセクションは次のとおりです。
同じフォームのすべてのセルに同じ再利用識別子を使用する必要があります。
そして、「ディスカッション」サブセクションは次のとおりです。
再利用識別子は、同じ一般的な構成からセルのコンテンツを除いたTable Viewのセル(行)に関連付けられます。
これらのステートメントは、dequeueReusableCellWithIdentifier
のtableView:cellForRowAtIndexPath:
の実装内でUITableViewDataSource
を使用する慣用的な方法が、それぞれに対して1つのセルオブジェクトを作成することを明確にしますvisiblerow使用可能な行の総数に関係なく。
最初の方法がUITableView
を実装するための最良の(そしてあなたが言ったように)方法だと思います。 2番目の方法では、表示されるすべての新しいセルにメモリが割り当てられ、メモリは再利用されません。
UITableView
は、識別子を持つセルを「テンプレート」として内部的に使用します。したがって、次に(テーブルとして読み取って)デックしようとすると、新しいセルが作成されますが、保存されたオブジェクトはテンプレートとして使用されます。そのため、コンテキストごとにセルの内容を反映するようにUIを更新する必要があります。
これは、UITableView
自体がセルのメモリ管理を行っていることも意味します。理論的には、可視セルと同数のUITableViewCell
オブジェクトのみが存在します。しかし、実際には、メモリが解放されるのをさらに2、3待っている可能性があります。
これは基本的にメモリを大幅に節約します。特に、1000個のセルがあるシナリオではそうです。
メモリが貴重なポータブルデバイスでは、メモリの割り当てを可能な限り最後まで延期し、ジョブが完了した時点でメモリを解放する必要があります。 dequeAndReusing
セルがこれを達成し、かなりうまくいきます。
一方、セルがカスタマイズされたセルである場合、ニブをロードしてそこから抽出する可能性が最も高いでしょう。この場合、識別子を使用してdeque OR nibからロードできます。手順に違いはありません。
唯一の違いはロード時間です。テーブルビューがテンプレートとして識別子セルを使用して新しいセルを作成できるようにしますcould nibからロードするよりもわずかに高速ですが、ほとんど目立たず、コンテキストに依存します。
セルを他のセルと区別するには、セルのタグプロパティを使用するか、カスタムセルを使用している場合、UITableViewCell
をサブクラス化するときに新しいプロパティをカスタムセルに導入することで非常に簡単です。
これらすべての後、あなたは動けず、まだセルを取得する必要がありますが、次のコードを試すことができます
UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]
一方、セルのコピーは作成されますが、既存のセルは返されませんが、内容は同じ値になるため、ある程度は避ける必要があります。