Nibから再利用可能なUITableViewCellをロードする


89

http://forums.macrumors.com/showthread.php?t=545061にあるスレッドで説明されている手法を使用して、カスタムUITableViewCellsを設計し、それらをうまくロードできます。ただし、このメソッドを使用すると、reuseIdentifierを使用してセルを初期化できなくなります。つまり、呼び出しごとに各セルのまったく新しいインスタンスを作成する必要があります。特定のセルタイプをキャッシュして再利用するための良い方法を見つけたが、Interface Builderでそれらを設計することはできますか?

回答:


74

適切なメソッドシグネチャでメソッドを実装するだけです。

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

このメソッドを実装する場所は?
クリシュナン


5
これは危険です。セルサブクラスに2つのサブクラスがあり、これらの両方を単一のテーブルビューで使用するとどうなりますか?彼らが再利用識別子の呼び出しをスーパーに送信すると、間違ったタイプのセルをデキューします.............. reuseIdentifierメソッドをオーバーライドする必要があると思いますが、置き換えられた識別子を返します。ストリング。
SK9

3
必ずそれはユニークだであるために、あなたが行うことができます:return NSStringFromClass([self class]);
ivanzoid

119

実際には、Interface Builderでセルを構築しているので、そこに再利用識別子を設定するだけです:

IB_reuse_identifier

または、Xcode 4を実行している場合は、[属性インスペクター]タブを確認します。

ここに画像の説明を入力してください

(編集:XCodeによってXIBが生成された後、空のUIViewが含まれますが、UITableViewCellが必要です。そのため、UIViewを手動で削除し、テーブルビューセルを挿入する必要があります。もちろん、IBは、UITableViewCellパラメータを表示しません。 UIView。)


このニブで作成されたセルを複数のセルに使用する場合、識別子を設定するにはどうすればよいですか?これにより、同じ識別子を持つ2つのセルが作成されます。
クリシュナン

4
一意の識別子とは考えないでください。タイプ名のように考えてください。
Tim Keating

Xcode 4.3.3の組み込みのインターフェイスビルダーを介して識別子を設定するオプションが表示されません。私は間違いなく、クラスをUITableViewCellサブクラスに設定しています。私はそれを逃しているだけですか、それともなくなっていますか?
タイラー

3
はい、問題を解決しました。インターフェイスビルダー(Xcode 4内)のUIViewオブジェクトから開始し、そのクラスをUITableViewCellに変更すると、再利用識別子などのセル固有のプロパティを取得できません。これを取得するには、空のxibから始めて、テーブルセルオブジェクトをドラッグします。これにより、セル固有のプロパティを編集できるようになります。
タイラー

1
@クリシュナンこのように考えてください。識別子Xのテーブルビューセルを作成するときは、「Xというラベルのプールからセルをください」と言っています。プールが存在し、そこに空きセルがある場合は、それが与えられます。それ以外の場合は、プールを作成し(必要な場合)、セルを更新し、「X」というラベルを付けて、それをユーザーに渡します。したがって、セルは一意にすることができます。たとえば、特定の識別子を持つセルが1つだけのプールを作成できますが、ライブラリは、メモリの割り当て/割り当て解除を回避するために、フリーリストのような戦略を使用します。
Tim Keating

66

現在、iOS 5にはそのための適切なUITableViewメソッドがあります。

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

10
承認された回答を含む、このスレッドの他の返信には、古いアドバイスが含まれています。
Kaelin Colclasure

これは下位互換ですか?たとえば、SDK 5.0をターゲットにして最小4.0のアプリを開発した場合、そのアプリはiOS 4.0を搭載したデバイスで実行されますか?
Abolfoooud

1
いいえ、iOS 5.0の新しいAPIのように、これには下位互換性がありません。
marzapower 2013年

:お使いのコントローラにこれを統合する方法の一例働いmindfiresolutions.com/...
mblackwell8

47

このコードを最初にどこで見つけたのか思い出せませんが、これまでのところ、うまく機能しています。

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

Interface Builderの設定例...

代替テキスト


12

私がこの質問に与えた答えを見てください:

Interface BuilderでNSCellサブクラスを設計することは可能ですか?

IBでUITableViewCellを設計するだけでなく、手動での配線や複数の要素の配置がすべて面倒なので、望ましいです。可能な限りすべての要素を不透明にするように注意している限り、パフォーマンスは問題ありません。IBでUITableViewCellのプロパティに再利用IDが設定されている場合、キューからデキューしようとするときに、一致する再利用IDをコードで使用します。

昨年WWDCのプレゼンターの何人かからも、IBでテーブルビューセルを作成するべきではないという話を聞きましたが、これは大量の二段ベッドです。


2
透明性が必要で、優れたスクロールパフォーマンスが必要な場合は、IBでテーブルビューセルを作成しないでください。特定のUIでは、透明度が必要です(テキストをグラフィックスでレンダリングする場合など)。古い(A4以前の)ハードウェアで適切なスクロールを実現する唯一の方法は、GPUが複数の透明なレイヤーを合成する必要がないように、コードでレンダリングすることです。
Nick Forge、

2
確かに、それでも、IBで構築されたセルの保守を容易にするために、古いデバイスではパフォーマンスをわずかに低下させる方がよい場合があります。また、この手法をテンプレートセルとして使用して、要素を描画し、カスタム描画メソッドとの合成を回避することもできます。
Kendall Helmstetter Gelner、2010


6

ここに別のオプションがあります:

NSString * cellId = @"reuseCell";  
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];

for (id obj in nibObjects)
{
    if ([obj isKindOfClass:[CustomTableCell class]])
    {
        cell = obj;
        [cell setValue:cellId forKey:@"reuseIdentifier"];
        break;
    }
}

これがこれまでに投稿された唯一のソリューションでありUITableViewCell、に一意の値を設定するためにカスタムをサブクラス化する必要がないことに注意してくださいreuseIdentifer。これは、元のopが実際に探していたものだと思います。
charshep、2012年

Appleがこれを使用するための私のアプリケーションを否定しないことを願っています...私のテーブルビューでは、セルを埋めるプロセスが静かに遅いため、これを使用して「静的」セルを取得しています。この方法では、1回実行するだけです(各行に異なる識別子を指定します)。ありがとうございました!
Campo

これを手動で設定するためのUITableViewCellメソッドがないため、非常に役立ちます。
Jesse、

2

同様の方法でカスタムビューセルを作成します。ただし、IBOutletを介してセルを接続します。

この[nib objectAt...]アプローチは、配列内のアイテムの位置の変更の影響を受けやすくなります。

UIViewControllerアプローチが良いです-ちょうどそれを試してみました、そして、それは素敵な十分に動作します。

だが...

すべてのケースでinitWithStyleコンストラクタは呼び出されないため、デフォルトの初期化は行われません。

initWithCoderまたはの使用についてさまざまな箇所を読みましたawakeFromNibが、これらのいずれかが正しい方法であるという決定的な証拠はありません。

メソッドでいくつかの初期化メソッドを明示的に呼び出すことを除いて、cellForRowAtIndexPathこれに対する答えはまだ見つかりません。


awakeFromNibは、NIBからロードされているオブジェクトに反応する正しい方法です。
Jon Hess

2

しばらく前にblog.atebits.comでこのトピックに関する素晴らしいブログ投稿を見つけました。それ以来、Loren Brichter ABTableViewCellクラスを使用してすべてのUITableViewCellsを実行し始めました。

すべてのウィジェットを配置するためのシンプルなコンテナーUIViewが作成され、スクロールは高速です。

これがお役に立てば幸いです。


2

この手法も機能し、メモリ管理のためにView Controllerにファンキーなivarを必要としません。ここで、カスタムテーブルビューセルは、「CustomCell.xib」という名前のxibにあります。

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }

1
アーカイブとアーカイブ解除は完全に不要です。
ブライアンヘンリー

1
デキューできないときはいつでも、nibからセルをロードすることに問題がなければ、アーカイブ/アーカイブ解除は不要です。ただし、nibからセルを1回だけロードする場合は、メモリにキャッシュする必要があります。UITableViewCellはNSCopyingを実装していないため、私はNSKeyedArchivingを使用してそのキャッシュを実現します。
Bill Garrison、

1
そうは言っても、UINibを使用してセルをロードすると、同じ効果が得られます。ディスクから1回ロードし、その後メモリからロードします。
Bill Garrison

2

ルイ法がうまくいきました。これは、nibからUITableViewCellを作成するために使用するコードです。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *simpleTableIdentifier = @"CustomCell";

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}         

return cell;
}

1

gustavogbソリューションは私にはうまくいきません、私が試したのは:

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

動作するようです。blogTableViewCellはセルのIBOutletであり、ChainesControllerはファイルの所有者です。


1

dequeueWithReuseIdentifier「再利用するセルオブジェクトを識別する文字列。デフォルトでは、再利用可能なセルの識別子はクラス名ですが、任意の値に変更できます。」に関するUITableViewドキュメントから。

-reuseIdentiferを自分でオーバーライドすることは危険です。セルサブクラスに2つのサブクラスがあり、これらの両方を単一のテーブルビューで使用するとどうなりますか?彼らが再利用識別子の呼び出しをスーパーに送信すると、間違ったタイプのセルをデキューします.............. reuseIdentifierメソッドをオーバーライドする必要があると思いますが、置き換えられた識別子を返します。ストリング。または、指定されていない場合は、クラスを文字列として返します。


0

その価値について、私はiPhone Tech Talksの1つでiPhoneエンジニアにこれについて尋ねました。彼の答えは、「はい、IBを使用してセルを作成することは可能です。しかし、できません。できません。できません」。


1
それは変です。NYトークでの少なくとも2つのトークには、IBで作成されたセルを使用するデモコードがありました。
Shawn Craver

3
AppleのAdvanced Table View Cellsサンプルプロジェクトでセルを作成するためにIBを使用しているので、これは信じられません。
iwasrobbされた2010年

それをありがとう。私がそれをするたびに、私は問題に遭遇しました。これが理由かもしれません
skorulis

彼はおそらくそれについて十分な知識を持っていませんでした。
aryaxt

0

私はベン・モッシャーによってリンクされたAppleの指示に従いました(ありがとう!)が、Appleが重要なポイントを省略していることに気付きました。彼らがIBで設計するオブジェクトは、UITableViewCellであり、そこからロードする変数です。しかし、実際にそれをUITableViewCellのカスタムサブクラスとして設定し、サブクラスのコードファイルを記述する場合は、コードにIBOutlet宣言とIBActionメソッドを記述し、それらをIBのカスタム要素にワイヤリングできます。そうすれば、これらの要素にアクセスするためにビュータグを使用する必要がなくなり、必要なあらゆる種類のクレイジーセルを作成できます。ココアタッチの天国です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.