XibファイルからカスタムUITableViewCellsをどのようにロードしますか?


293

質問は簡単です:UITableViewCellXibファイルからカスタムをどのようにロードしますか?これにより、Interface Builderを使用してセルを設計できます。メモリ管理の問題により、答えは明らかに単純ではありません。このスレッドは問題に言及し、解決策を提案しますが、NDAのリリース前であり、コードが不足しています。決定的な答えを提供せずに問題を議論する長いスレッドがあります。

ここに私が使用したいくつかのコードがあります:

static NSString *CellIdentifier = @"MyCellIdentifier";

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

このコードを使用するには、の新しいサブクラスであるMyCell.m / .hを作成し、必要なコンポーネントをUITableViewCell追加IBOutletsします。次に、新しい「空のXIB」ファイルを作成します。IBでXibファイルを開き、UITableViewCellオブジェクトを追加し、その識別子を「MyCellIdentifier」に設定し、そのクラスをMyCellに設定してコンポーネントを追加します。最後に、IBOutletsをコンポーネントに接続します。IBでファイルの所有者を設定していないことに注意してください。

他のメソッドは、ファイルの所有者の設定を推奨し、追加のファクトリクラスを介してXibがロードされない場合にメモリリークを警告します。上記のInstruments / Leaksでテストしたところ、メモリリークはありませんでした。

では、Xibからセルをロードする標準的な方法は何ですか?ファイルの所有者を設定しますか?工場は必要ですか?もしそうなら、ファクトリーのコードはどのように見えますか?複数のソリューションがある場合は、それぞれの長所と短所を明確にしましょう...


2
誰かが件名を編集して実際に質問をすることはできますか、すなわち「XibファイルからカスタムUITableViewCellsをどのようにロードしますか?」(stackoverflowでこれが不可能な場合は無視してください。)
Steven Fisher

1
iOS 5以降の場合、これはソリューションです:stackoverflow.com/questions/15591364/…、これはgiuseppeのソリューションと同じです。
マットベッカー

クイックノート、単純(2013環境)の答えここstackoverflow.com/questions/15378788/... jamihash
Fattie

回答:


288

元の著者がIBエンジニアが推奨した 2つの方法を次に示します。

詳細については、実際の投稿を参照してください。より簡単に思えるので、私は方法#2を好みます。

方法1:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Create a temporary UIViewController to instantiate the custom cell.
        UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:@"BDCustomCell" bundle:nil];
        // Grab a pointer to the custom cell.
        cell = (BDCustomCell *)temporaryController.view;
        [[cell retain] autorelease];
        // Release the temporary UIViewController.
        [temporaryController release];
    }

    return cell;
}

方法#2:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BDCustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];
    }

    return cell;
}

更新(2014): メソッド#2はまだ有効ですが、ドキュメントはありません。以前は公式ドキュメントにありましたたが、今ではストーリーボードを優先して削除されています。

私はGithubに作業例を投稿しました:https :
//github.com/bentford/NibTableCellExample

Swift 4.2用に編集

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    self.tblContacts.register(UINib(nibName: CellNames.ContactsCell, bundle: nil), forCellReuseIdentifier: MyIdentifier)
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: MyIdentifier, for: indexPath) as! ContactsCell

    return cell
}

1
方法1では、「cell =(BDCustomCell *)[[temporaryController.view maintain] autorelease];」のようなことをすべきではありません。だから一時的なコントローラーがリリースされたときにセルが解放されませんか?
Tod Cunningham、

うーん。#2に関するドキュメントでは、XIBファイルのセルの所有者を既知のコントローラークラスに設定するように指示されています。読み込み中に所有者を設定する場合は、おそらく問題ではありません。
オスカー

@OscarGoldman XIBファイル内のセルの所有者はクラス(つまり、所有者のタイプ)です。loadNibNamed:owner:options:内のセルの所有者は、XIBで指定されたタイプのオブジェクトです。
ベンフォード

2
@CoolDocManオプション#2は引き続き機能します。問題はおそらくペン先にあります。以下に例を示します。github.com
bentford

2
この超古いコードがなぜそれほど高くランク付けされているのですか?Stackoverflowは何かをします:/
ニコS.

304

正しい解決策はこれです:

- (void)viewDidLoad
{
    [super viewDidLoad];
    UINib *nib = [UINib nibWithNibName:@"ItemCell" bundle:nil];
    [[self tableView] registerNib:nib forCellReuseIdentifier:@"ItemCell"];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Create an instance of ItemCell
    PointsItemCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ItemCell"];

    return cell;
}

iOS5アプリが壊れるのでしょうか?私は本当にUINibを見たことがない
アダムウェイト

@AdamWaite iOS 5以降ではNIBファイルの登録が機能するため、iOS 5アプリが壊れることはありません。そしてUINibも、iOSの4以来の存在
Mecki

:良い例については、ここではトップの答えで参照Gitのレポをチェックstackoverflow.com/questions/18746929/...
netigger

39

登録

iOS 7以降、このプロセスは(swift 3.0)に簡略化されました。

// For registering nib files
tableView.register(UINib(nibName: "MyCell", bundle: Bundle.main), forCellReuseIdentifier: "cell")

// For registering classes
tableView.register(MyCellClass.self, forCellReuseIdentifier: "cell")

)これは、.xibor .stroyboardファイル内のセルをプロトタイプセルとして作成することでも実現できます。それらにクラスをアタッチする必要がある場合は、セルのプロトタイプを選択し、対応するクラスを追加できます(UITableViewCellもちろん、の子孫でなければなりません)。

デキュー

その後、(swift 3.0)を使用してデキューしました:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

    cell.textLabel?.text = "Hello"

    return cell
}

違いは、この新しいメソッドはセルをデキューするだけでなく、存在しない場合(つまりif (cell == nil)、シェイナンを行う必要がない場合)を作成し、セルは上記の例と同じように使用できることです。

警告tableView.dequeueReusableCell(withIdentifier:for:)には新しい動作があり、他の(なしでindexPath:)を呼び出すと、古い動作を取得します。この動作を確認しnilてインスタンス化する必要があるため、UITableViewCell?戻り値に注意してください。

if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCellClass
{
    // Cell be casted properly
    cell.myCustomProperty = true
}
else
{
    // Wrong type? Wrong identifier?
}

そしてもちろん、セルに関連付けられたクラスのタイプは、UITableViewCellサブクラスの.xibファイルで定義したタイプ、または他のレジスタメソッドを使用したタイプです。

構成

理想的には、セルは、それらを登録したときまでに、外観とコンテンツの配置(ラベルやイメージビューなど)に関してすでに構成されており、cellForRowAtIndexPathメソッドでセルに入力するだけです。

すべて一緒に

class MyCell : UITableViewCell
{
    // Can be either created manually, or loaded from a nib with prototypes
    @IBOutlet weak var labelSomething : UILabel? = nil
}

class MasterViewController: UITableViewController 
{
    var data = ["Hello", "World", "Kinda", "Cliche", "Though"]

    // Register
    override func viewDidLoad()
    {
        super.viewDidLoad()

        tableView.register(MyCell.self, forCellReuseIdentifier: "mycell")
        // or the nib alternative
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return data.count
    }

    // Dequeue
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "mycell", for: indexPath) as! MyCell

        cell.labelSomething?.text = data[indexPath.row]

        return cell
    }
}

そしてもちろん、これはすべて同じ名前のObjCで利用できます。


ここにObjCのバージョンがある:[self.tableView registerNib:[UINib nibWithNibName:@"BlaBlaTableViewCell" bundle:nil] forCellReuseIdentifier:kCellIdentifier];
ゼブ

33

Shawn Craverの回答を取り、少し整理しました。

BBCell.h:

#import <UIKit/UIKit.h>

@interface BBCell : UITableViewCell {
}

+ (BBCell *)cellFromNibNamed:(NSString *)nibName;

@end

BBCell.m:

#import "BBCell.h"

@implementation BBCell

+ (BBCell *)cellFromNibNamed:(NSString *)nibName {
    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    BBCell *customCell = nil;
    NSObject* nibItem = nil;
    while ((nibItem = [nibEnumerator nextObject]) != nil) {
        if ([nibItem isKindOfClass:[BBCell class]]) {
            customCell = (BBCell *)nibItem;
            break; // we have a winner
        }
    }
    return customCell;
}

@end

私はすべてのUITableViewCellのBBCellのサブクラスを作成し、標準を置き換えます

cell = [[[BBDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BBDetailCell"] autorelease];

と:

cell = (BBDetailCell *)[BBDetailCell cellFromNibNamed:@"BBDetailCell"];

16

私はベントフォードの方法#2を使用しました:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BDCustomCell"];
    if (cell == nil) {
        // Load the top-level objects from the custom cell XIB.
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BDCustomCell" owner:self options:nil];
        // Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
        cell = [topLevelObjects objectAtIndex:0];
    }

    return cell;
}

動作しますが、カスタムUITableViewCell .xibファイルでファイルの所有者への接続に注意してください。

渡すことによって、owner:selfあなたにloadNibNamed声明、あなたが設定されUITableViewController、あなたのファイルの所有者としてUITableViewCell

IBのヘッダーファイルにドラッグアンドドロップしてアクションとアウトレットを設定すると、デフォルトでそれらがファイルの所有者として設定されます。

ではloadNibNamed:owner:options、Appleのコードがにプロパティを設定しようとしますUITableViewController。それが所有者だからです。ただし、そこで定義されているプロパティがないため、キー値のコーディングに準拠しているというエラーが発生します

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason:     '[<MyUITableViewController 0x6a383b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key myLabel.'

代わりにイベントがトリガーされると、NSInvalidArgumentExceptionが発生します。

-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyUITableViewController switchValueDidChange:]: unrecognized selector sent to instance 0x8e9acd0'
*** First throw call stack:
(0x1903052 0x15eed0a 0x1904ced 0x1869f00 0x1869ce2 0x1904ec9 0x5885c2 0x58855a 0x62db76 0x62e03f 0x77fa6c 0x24e86d 0x18d7966 0x18d7407 0x183a7c0 0x1839db4 0x1839ccb 0x1f8b879 0x1f8b93e 0x585a9b 0xb904d 0x2c75)
terminate called throwing an exceptionCurrent language:  auto; currently objective-c

簡単な回避策はUITableViewCell、ファイルの所有者ではなくInterface Builder接続を指すことです。

  1. ファイルの所有者を右クリックして、接続のリストを表示します
  2. Command-Shift-4でスクリーンキャプチャを取得します(ドラッグして、キャプチャする領域を選択します)
  3. xファイルの所有者からの接続を取り出します
  4. オブジェクト階層のUITableCellを右クリックして、接続を再度追加します。

私はあなたが言及した問題がありましたが、Fileの所有者ではなくUITableViewCellへの接続をどのようにポイントするのですか?手順がわかりません。たとえば、スクリーンショットを撮る必要があるのはなぜですか。アウトレットの横にある追加ボタンをクリックしても何も起こらない
xu huanze 2013年

@xuhuanze私はスクリーンショットを撮ることを提案したので、Fileの所有者がすでに接続しているものの記録を持っています。その後、同じ接続を再作成できます。接続を追加するには、クリックするだけでなく、ドラッグアンドドロップする必要があります。
funroll 2013年

おかげで、「このクラスはキーのコーディングに準拠したキー値ではありません」という問題があり、あなたの助けによってそれを解決しました。カスタムセルクラスとして使用するUITableViewCellのクラスも自分のクラスに変更する必要があることを他の人に伝えたいと思います。
Denis Kutlubaev 2013

14

私はこれらの答えが好きではないため、投稿することにしました。物事は常によりシンプルになる可能性があり、これは私が見つけた最も簡潔な方法です。

1.必要に応じて、Interface BuilderでXibをビルドします

  • ファイルの所有者をクラスNSObjectに設定する
  • UITableViewCellを追加し、そのクラスをMyTableViewCellSubclassに設定します-IBがクラッシュした場合(これを書いている時点でXcode> 4で発生します)、UIViewを使用して、Xcode 4のインターフェイスを実行します。
  • このセル内にサブビューをレイアウトし、IBOutlet接続を.hまたは.m(.mが私の好みです)の@インターフェースに接続します。

2. UIViewControllerまたはUITableViewControllerサブクラス内

@implementation ViewController

static NSString *cellIdentifier = @"MyCellIdentier";

- (void) viewDidLoad {

    ...
    [self.tableView registerNib:[UINib nibWithNibName:@"MyTableViewCellSubclass" bundle:nil] forCellReuseIdentifier:cellIdentifier];
}

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCellSubclass *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    ...

    return cell;
}

3. MyTableViewCellSubclass

- (id) initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        ...
    }

    return self;
}

9

インターフェイスビルダーを使用してセルを作成している場合は、インスペクターで識別子を設定していることを確認してください。次に、dequeueReusableCellWithIdentifierを呼び出すときに同じであることを確認します。

テーブルを多用するプロジェクトで誤っていくつかの識別子を設定するのを忘れており、パフォーマンスの変化は昼と夜のようでした。


8

XIBからUITableViewCellsをロードすると、多くのコードが節約されますが、通常は恐ろしいスクロール速度になります(実際には、XIBではなく、UIViewを過度に使用することが原因です)。

これをご覧になることをお勧めします:リンク参照


6

XIBからカスタムセルを作成するために使用してきたクラスメソッドは次のとおりです。

+ (CustomCell*) createNewCustomCellFromNib {

    NSArray* nibContents = [[NSBundle mainBundle]
                            loadNibNamed:@"CustomCell" owner:self options:NULL];

    NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
    CustomCell *customCell= nil;
    NSObject* nibItem = nil;

    while ( (nibItem = [nibEnumerator nextObject]) != nil) {

        if ( [nibItem isKindOfClass: [CustomCell class]]) {
            customCell = (CustomCell*) nibItem;

            if ([customCell.reuseIdentifier isEqualToString: @"CustomCell"]) {
                break; // we have a winner
            }
            else
                fuelEntryCell = nil;
        }
    }
    return customCell;
}

次に、XIBでクラス名を設定し、識別子を再利用します。その後、ビューコントローラーでそのメソッドを呼び出す代わりに、

[[UITableViewCell] alloc] initWithFrame:]

それは十分に速く、私の出荷アプリケーションの2つで使用されています。これはを呼び出すよりも信頼性が高く、[nib objectAtIndex:0]少なくとも私の考えでは、Stephan Burlotの例よりも信頼性が高いです。なぜなら、正しいタイプのXIBからのみビューを取得することが保証されているからです。


5

正しい解決策はこれです

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"CustomCell"];
}

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

4

NIBのリロードにはコストがかかります。一度ロードして、セルが必要なときにオブジェクトをインスタンス化することをお勧めします。このメソッドを使用して、UIImageViewsなどを複数のセルであってもnibに追加できることに注意してください(Appleの「registerNIB」iOS5は、最上位オブジェクトを1つしか許可しません-バグ10580062「iOS5 tableView registerNib:過度に制限的」

だから私のコードは下にあります-NIBを一度読みました(私が行ったような初期化またはviewDidloadで-何でも。その後、オブジェクトにnibをインスタンス化し、必要なものを選択します。これはnibをロードするよりもはるかに効率的です。何度も。

static UINib *cellNib;

+ (void)initialize
{
    if(self == [ImageManager class]) {
        cellNib = [UINib nibWithNibName:@"ImageManagerCell" bundle:nil];
        assert(cellNib);
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"TheCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if(cell == nil) {
        NSArray *topLevelItems = [cellNib instantiateWithOwner:nil options:nil];
        NSUInteger idx = [topLevelItems indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
                            {
                                UITableViewCell *cell = (UITableViewCell *)obj;
                                return [cell isKindOfClass:[UITableViewCell class]] && [cell.reuseIdentifier isEqualToString:cellID];
                            } ];
        assert(idx != NSNotFound);
        cell = [topLevelItems objectAtIndex:idx];
    }
    cell.textLabel.text = [NSString stringWithFormat:@"Howdie %d", indexPath.row];

    return cell;
}

4

これを確認してください-http://eppz.eu/blog/custom-uitableview-cell/-コントローラ実装で1行になる小さなクラスを使用する本当に便利な方法:

-(UITableViewCell*)tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath
{
    return [TCItemCell cellForTableView:tableView
                          atIndexPath:indexPath
                      withModelSource:self];
}

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


3

これを行う正しい方法は、UITableViewCellサブクラスの実装、ヘッダー、およびXIBを作成することです。XIBでビューを削除し、テーブルセルを追加します。クラスをUITableViewCellサブクラスの名前として設定します。ファイル所有者の場合は、UITableViewControllerサブクラスのクラス名にします。tableViewCellアウトレットを使用して、ファイル所有者をセルに接続します。

ヘッダーファイル:

UITableViewCell *_tableViewCell;
@property (assign) IBOutlet UITableViewCell *tableViewCell;

実装ファイルで:

@synthesize tableViewCell = _tableViewCell;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *kCellIdentifier = @"reusableCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:kCellIdentifier owner:self options:nil];
        cell = _tableViewCell;
        self.tableViewCell = nil;
    }

    return cell;
}

3

これを行うにはIBOutlet UITableViewCell *cell、コントローラークラスでを宣言します。次に、NSBundle loadNibNamedクラスメソッドを呼び出しUITableViewCellます。これにより、上で宣言したセルにがフィードされます。

xibの場合、空のxibを作成し、UITableViewCell必要に応じて設定できるオブジェクトをIBに追加します。このビューはIBOutlet、コントローラークラスのセルに接続されます。

- (UITableViewCell *)tableView:(UITableView *)table
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%@ loading RTEditableCell.xib", [self description] );

    static NSString *MyIdentifier = @"editableCellIdentifier";
    cell = [table dequeueReusableCellWithIdentifier:MyIdentifier];

    if(cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"RTEditableCell"
                                      owner:self
                                    options:nil];
    }

    return cell;
}

NSBundleの追加loadNibNamed(ADCログイン)

cocoawithlove.comの記事(電話番号のサンプルアプリを入手)からコンセプトを入手しました


3
  1. AbcViewCellから独自のカスタマイズされたクラスサブクラスを作成しますUITableViewCell(クラスファイル名とnibファイル名が同じであることを確認してください)

  2. この拡張クラスメソッドを作成します。

    extension UITableViewCell {
        class func fromNib<T : UITableViewCell>() -> T {
            return Bundle.main.loadNibNamed(String(describing: T.self), owner: nil, options: nil)?[0] as! T
        }
    }
  3. これを使って。

    let cell: AbcViewCell = UITableViewCell.fromNib()


2

最初にカスタムセルファイル#import "CustomCell.h"をインポートしてから、以下のようにデリゲートメソッドを変更します。

- (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;
}

2

スウィフト4.2とXcode 10

3つのXIBセルファイルがあります

ViewDidLoadで次のようにXIBファイルを登録します...

これが最初のアプローチです

tableView.register(UINib.init(nibName: "XIBCell", bundle: nil), forCellReuseIdentifier: "cell1")
tableView.register(UINib.init(nibName: "XIBCell2", bundle: nil), forCellReuseIdentifier: "cell2")
//tableView.register(UINib.init(nibName: "XIBCell3", bundle: nil), forCellReuseIdentifier: "cell3")

2番目のアプローチは、cellForRowAt indexPathに XIBファイルを直接登録します。

これは私のテーブルビューデリゲート関数です

//MARK: - Tableview delegates
override func numberOfSections(in tableView: UITableView) -> Int {

    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return 6
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //This is first approach
    if indexPath.row == 0 {//Load first XIB cell
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! XIBCell
        return placeCell
    //Second approach
    } else if indexPath.row == 5 {//Load XIB cell3
        var cell = tableView.dequeueReusableCell(withIdentifier:"cell3") as? XIBCell3
        if cell == nil{
            let arrNib:Array = Bundle.main.loadNibNamed("XIBCell3",owner: self, options: nil)!
            cell = arrNib.first as? XIBCell3
        }

        //ADD action to XIB cell button
        cell?.btn.tag = indexPath.row//Add tag to button
        cell?.btn.addTarget(self, action: #selector(self.bookbtn1(_:)), for: .touchUpInside);//selector

        return cell!
    //This is first approach
    } else {//Load XIB cell2
        let placeCell = tableView.dequeueReusableCell(withIdentifier: "cell2") as! XIBCell2

        return placeCell
    }

}

1

これが私の方法です:XIBファイルからカスタムUITableViewCellsをロードしています…さらに別の方法

アイデアは、のSampleCellサブクラスを作成することです UITableViewCellIBOutlet UIView *content財産、あなたがコードから設定する必要がある各カスタムサブビューのプロパティ。次に、SampleCell.xibファイルを作成します。このnibファイルで、ファイル所有者をSampleCellに変更します。UIViewニーズに合ったサイズのコンテンツを追加します。必要なすべてのサブビュー(ラベル、画像ビュー、ボタンなど)を追加して構成します。最後に、コンテンツビューとサブビューをファイル所有者にリンクします。


1

セルを登録するための一般的なアプローチを次に示しますUITableView

protocol Reusable {
    static var reuseID: String { get }
}

extension Reusable {
    static var reuseID: String {
        return String(describing: self)
    }
}

extension UITableViewCell: Reusable { }

extension UITableView {

func register<T: UITableViewCell>(cellClass: T.Type = T.self) {
    let bundle = Bundle(for: cellClass.self)
    if bundle.path(forResource: cellClass.reuseID, ofType: "nib") != nil {
        let nib = UINib(nibName: cellClass.reuseID, bundle: bundle)
        register(nib, forCellReuseIdentifier: cellClass.reuseID)
    } else {
        register(cellClass.self, forCellReuseIdentifier: cellClass.reuseID)
    }
}

説明:

  1. Reusableプロトコルは、クラス名からセルIDを生成します。必ず規則に従ってくださいcell ID == class name == nib name
  2. UITableViewCellReusableプロトコルに準拠しています。
  3. UITableView 拡張機能は、nibまたはクラスを介してセルを登録する際の違いを抽象化します。

使用例:

override func viewDidLoad() {
    super.viewDidLoad()
    let tableView = UITableView()
    let cellClasses: [UITableViewCell.Type] = [PostCell.self, ProfileCell.self, CommentCell.self]
    cellClasses.forEach(tableView.register)
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: PostCell.self.reuseID) as? PostCell
    ...
    return cell
}

0

正規の方法があるかどうかはわかりませんが、ここに私の方法があります:

  • ViewControllerのxibを作成する
  • ファイル所有者クラスをUIViewControllerに設定します。
  • ビューを削除し、UITableViewCellを追加します。
  • UITableViewCellのクラスをカスタムクラスに設定します
  • UITableViewCellの識別子を設定します。
  • ビューコントローラービューのアウトレットをUITableViewCellに設定します。

そして、このコードを使用してください:

MyCustomViewCell *cell = (MyCustomViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
  UIViewController* c = [[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
  cell = (MyCustomViewCell *)c.view;
  [c release];
}

あなたの例では、

[nib objectAtIndex:0]

Appleがxib内のアイテムの順序を変更すると、壊れることがあります。


私にとって、これは常に新しいインスタンスを作成することになります。デキューは毎回nilを返すようです。
奇妙な

0
 NSString *CellIdentifier = [NSString stringWithFormat:@"cell %ld %ld",(long)indexPath.row,(long)indexPath.section];


    NewsFeedCell *cell = (NewsFeedCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    cell=nil;

    if (cell == nil)
    {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewsFeedCell" owner:nil options:nil];

        for(id currentObject in topLevelObjects)
        {
            if([currentObject isKindOfClass:[NewsFeedCell class]])
            {
                cell = (NewsFeedCell *)currentObject;
                break;
            }
        }
}
return cell;

0

この拡張機能にはXcode7 beta6が必要です

extension NSBundle {
    enum LoadViewError: ErrorType {
        case ExpectedXibToExistButGotNil
        case ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        case XibReturnedWrongType
    }

    func loadView<T>(name: String) throws -> T {
        let topLevelObjects: [AnyObject]! = loadNibNamed(name, owner: self, options: nil)
        if topLevelObjects == nil {
            throw LoadViewError.ExpectedXibToExistButGotNil
        }
        if topLevelObjects.count != 1 {
            throw LoadViewError.ExpectedXibToContainJustOneButGotDifferentNumberOfObjects
        }
        let firstObject: AnyObject! = topLevelObjects.first
        guard let result = firstObject as? T else {
            throw LoadViewError.XibReturnedWrongType
        }
        return result
    }
}

カスタムUITableViewCellを1つだけ含むXibファイルを作成します。

それをロードします。

let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")

0
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cellReuseIdentifier = "collabCell"
            var cell:collabCell! = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? collabCell
            if cell == nil {
                tableView.register(UINib(nibName: "collabCell", bundle: nil), forCellReuseIdentifier: cellReuseIdentifier)
                cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! collabCell!
            }


            return cell

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