Domanda

La domanda è semplice:Come si carica custom UITableViewCell dai file Xib?In questo modo puoi utilizzare Interface Builder per progettare le tue celle.La risposta a quanto pare non è semplice a causa di problemi di gestione della memoria. Questo filo menziona il problema e suggerisce una soluzione, ma è pre-rilascio NDA e manca di codice.Ecco un filo lungo che discute la questione senza fornire una risposta definitiva.

Ecco alcuni codici che ho usato:

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

Per utilizzare questo codice, crea MyCell.m/.h, una nuova sottoclasse di UITableViewCell e aggiungi IBOutlets per i componenti che desideri.Quindi crea un nuovo file "Empty XIB".Apri il file Xib in IB, aggiungi a UITableViewCell oggetto, imposta il suo identificatore su "MyCellIdentifier" e imposta la sua classe su MyCell e aggiungi i tuoi componenti.Infine, collega il IBOutlets ai componenti.Tieni presente che non abbiamo impostato il proprietario del file in IB.

Altri metodi consigliano l'impostazione del proprietario del file e avvisano di perdite di memoria se Xib non viene caricato tramite una classe factory aggiuntiva.Ho testato quanto sopra in Strumenti/Perdite e non ho riscontrato perdite di memoria.

Allora qual è il modo canonico per caricare le celle da Xibs?Impostiamo il proprietario del file?Abbiamo bisogno di una fabbrica?Se sì, qual è il codice della fabbrica?Se le soluzioni sono più di una, chiariamo i pro e i contro di ciascuna di esse...

È stato utile?

Soluzione

Qui ci sono due metodi che la autore afferma originali è stato consigliato da un ingegnere IB .

Vedi il post vero e proprio per maggiori dettagli. Io preferisco il metodo # 2 come sembra più semplice.

Metodo # 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;
}

Metodo # 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;
}

Aggiorna (2014): Metodo # 2 è ancora valida, ma non v'è alcuna documentazione per più. Ha usato per essere nella documentazione ufficiale ma è stato rimosso a favore di storyboard.

ho postato un esempio funzionante su Github:
https://github.com/bentford/NibTableCellExample

modifica per 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
}

Altri suggerimenti

La soluzione giusta è questa:

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

Registrati

Dopo iOS 7, questo processo è stato semplificato fino a (veloce 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")

(Nota) Ciò è ottenibile anche creando le celle nel file .xib O .stroyboard file, come celle prototipo.Se devi allegare una classe ad essi, puoi selezionare il prototipo della cella e aggiungere la classe corrispondente (deve essere un discendente di UITableViewCell, Ovviamente).

Decoda

E successivamente, rimosso dalla coda utilizzando (veloce 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
}

La differenza è che questo nuovo metodo non solo rimuove dalla coda la cella, ma crea anche se inesistente (ciò significa che non devi fare if (cell == nil) imbrogli) e la cella è pronta per l'uso proprio come nell'esempio sopra.

(Avvertimento) tableView.dequeueReusableCell(withIdentifier:for:) ha il nuovo comportamento, se chiami l'altro (senza indexPath:) ottieni il vecchio comportamento, in cui devi verificare nil e fai un'istanza tu stesso, nota il UITableViewCell? valore di ritorno.

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

E, naturalmente, il tipo della classe associata alla cella è quella definita nel file .xib per UITableViewCell sottoclasse o, in alternativa, utilizzando l'altro metodo di registro.

Configurazione

Idealmente, le tue celle sono già configurate in termini di aspetto e posizionamento dei contenuti (come etichette e visualizzazioni di immagini) nel momento in cui le registri, e sul cellForRowAtIndexPath metodo è sufficiente compilarli.

Tutti insieme

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

E, naturalmente, tutto questo è disponibile in ObjC con gli stessi nomi.

Ha preso la risposta di Shawn Craver e ripulito tutto un po '.

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

io faccio nuove tutte le sottoclassi di mio UITableViewCell di BBCell, e quindi sostituire lo standard

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

con:

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

ho usato di bentford Metodo # 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;
}

Funziona, ma attenzione per le connessioni a proprietario file del file nella vostra abitudine UITableViewCell .xib.

Passando owner:self nell'istruzione loadNibNamed, è possibile impostare il UITableViewController come proprietario del file della vostra UITableViewCell.

Se si trascina al file di intestazione in IB per impostare le azioni e le prese, che li impostato come proprietario del file di default.

In loadNibNamed:owner:options, il codice di Apple cercherà di impostare le proprietà sul vostro UITableViewController, dato che è il proprietario. Ma non si dispone di queste proprietà definite lì, in modo da ottenere un errore di essere il valore della chiave di codifica compatibile :

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

Se un evento viene attivato, invece, si otterrà un 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

Una soluzione semplice è quello di indicare le connessioni Interface Builder al UITableViewCell invece di proprietario di file:

  1. Fare clic destro sul file del proprietario per tirare su l'elenco dei collegamenti
  2. Date di cattura schermo con Comando-Maiuscole-4 (trascinare per selezionare l'area da catturare)
  3. x le connessioni dal proprietario del file
  4. Fare clic destro sul UITableCell nella gerarchia di oggetti e aggiungere nuovamente i collegamenti.

ho deciso di inviare in quanto non mi piace nessuna di queste risposte - cose possono sempre essere più semplice e questo è di gran lunga il modo più conciso che ho trovato

.

1. Costruisci la tua Xib in Interface Builder come piace a te

  • Imposta proprietario del file di classe NSObject
  • Aggiungi un UITableViewCell e impostare questa categoria per MyTableViewCellSubclass - in caso di blocco IB (accade in Xcode> 4 stesura di questo documento), basta usare un UIView di fare l'interfaccia in Xcode 4, se avete ancora è che in giro
  • Layout tuoi subviews dentro questa cella e attaccare le connessioni IBOutlet al @interface nel .h o .m (.m è la mia preferenza)

2. Nella tua UIViewController o UITableViewController sottoclasse

@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. Nel vostro MyTableViewCellSubclass

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

    return self;
}

Se stai usando Interface Builder per fare le cellule, verificare di aver impostato l'identificatore nella finestra di ispezione. Poi controllare che è lo stesso quando si chiama dequeueReusableCellWithIdentifier.

Ho dimenticato accidentalmente impostare alcuni identificatori in un progetto di tavolo pesante, e il cambiamento delle prestazioni era come notte e giorno.

Caricamento UITableViewCells da XIBs fa risparmiare un sacco di codice, ma di solito si traduce in velocità di scorrimento orribile (in realtà, non è la XIB ma l'uso eccessivo di UIViews che causano questo).

vi consiglio di dare un'occhiata a questo: link di riferimento

Ecco il metodo di classe che ho usato per la creazione di cellule personalizzate fuori XIBs:

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

Poi, nel XIB, ho impostato il nome della classe, e il riutilizzo identificatore. Dopo di che, posso solo chiamare quel metodo a mio avviso controllore al posto del

[[UITableViewCell] alloc] initWithFrame:]

E 'un sacco abbastanza veloce, e di essere utilizzato in due delle mie applicazioni di spedizione. E 'più affidabile di chiamare [nib objectAtIndex:0], e nella mia mente, almeno, più affidabile di esempio di Stephan Burlot perché avrete la garanzia di afferrare solo una visione di un XIB che è il tipo giusto.

soluzione corretta è questo

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

Ricaricare il pennino è costoso. Meglio per caricare una volta, poi istanziare gli oggetti quando si ha bisogno di una cella. Si noti che è possibile aggiungere UIImageViews ecc per il pennino, anche più celle, utilizzando questo metodo (di Apple "registerNIB" iOS5 consente solo un oggetto di alto livello - Bug 10.580.062 "IOS5 tableView registerNib: troppo restrittiva"

Quindi il mio codice è qui sotto - si legge nel NIB una volta (in inizializzazione come ho fatto io o in viewDidLoad -.. Qualunque Da allora in poi, si crea un'istanza il pennino in oggetti poi scegliere quello che vi serve Questo è molto più efficiente rispetto caricare il pennino più e più volte.

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

Controlla questo - http://eppz.eu/blog/custom-uitableview-cell / - davvero conveniente modo utilizzando una piccola classe che finisce una riga per l'attuazione di controllo:

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

entrare descrizione dell'immagine qui

Il modo corretto per farlo è quello di creare un'implementazione UITableViewCell sottoclasse, intestazione e XIB. Nel XIB eliminare visualizzazioni e basta aggiungere una cella di tabella. Impostare la classe come il nome della sottoclasse UITableViewCell. Per il proprietario del file, ne fanno l'UITableViewController nome della classe sottoclasse. Collegare il proprietario del file alla cella utilizzando la presa di tableViewCell.

Nel file di intestazione:

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

Nel file di implementazione:

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

Quello che faccio per questo è dichiarare un IBOutlet UITableViewCell *cell nella classe controller. Quindi richiamare il metodo della classe NSBundle loadNibNamed, che alimenterà il UITableViewCell alla cella dichiarato sopra.

Per la XI ter creerò un XI ter vuota e aggiungere l'oggetto in IB UITableViewCell dove può essere configurato in base alle esigenze. Questo punto di vista è poi collegato al IBOutlet cella nella classe controller.

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

aggiunte NSBundle loadNibNamed (ADC login)

cocoawithlove.com articolo proviene il concetto da (ottenere il campione i numeri di telefono app)

Per prima importare il file cellulare #import "CustomCell.h" personalizzato e quindi modificare il metodo delegato come indicato qui sotto:

- (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. Crea il tuo personalizzato sottoclasse classe AbcViewCell da UITableViewCell (Assicurarsi che il nome del file di classe e il nome del file pennino sono gli stessi)

  2. Crea questo metodo di classe di estensione.

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

    let cell: AbcViewCell = UITableViewCell.fromNib()

Swift 4.2 e Xcode 10

Ho tre file di cellule XIB

in viewDidLoad registrare i file XIB come questo ...

Questo è il primo approccio

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")

Secondo approccio registrare direttamente i file XIB in cellForRowAt indexPath:

Questo è il mio funzioni delegate Tableview

//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
    }

}

Ecco il mio metodo per che: Loading UITableViewCells da XIB Files ... ancora un altro metodo

L'idea è quella di creare una sottoclasse SampleCell del UITableViewCell con una proprietà IBOutlet UIView *content e una proprietà per ogni visualizzazione secondaria personalizzata è necessario configurare dal codice. Quindi per creare un file SampleCell.xib. In questo file pennino, cambiare il proprietario del file per SampleCell. Aggiungi un UIView contenuti dimensionato per soddisfare le vostre esigenze. Aggiungere e configurare tutte le subviews (etichetta, vista di immagine, pulsanti, ecc) che si desidera. Infine, collegare la vista contenuto e le subviews al proprietario del file.

Ecco un approccio universale per la registrazione di cellule in 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)
    }
}

Spiegazione:

  1. protocollo Reusable genera ID cella dal suo nome di classe. Assicuratevi di seguire la convenzione:. cell ID == class name == nib name
  2. UITableViewCell conforme al protocollo Reusable.
  3. estensione UITableView astrae la differenza nella registrazione cellule tramite pennino o di classe.

Esempio di utilizzo:

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
}

Non so se esiste un modo canonico, ma ecco il mio metodo:

  • Crea un xib per un ViewController
  • Imposta la classe Proprietario file su UIViewController
  • Elimina la vista e aggiungi un UITableViewCell
  • Imposta la classe del tuo UITableViewCell sulla tua classe personalizzata
  • Imposta l'identificatore del tuo UITableViewCell
  • Imposta l'uscita della vista del controller di visualizzazione su UITableViewCell

E usa questo codice:

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

Nel tuo esempio, utilizzando

[nib objectAtIndex:0]

potrebbe rompersi se Apple cambia l'ordine degli elementi nello xib.

 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;

Questa estensione richiede 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
    }
}

Crea un file di Xib che contiene solo 1 personalizzato UITableViewCell.

caricarlo.

let cell: BacteriaCell = try NSBundle.mainBundle().loadView("BacteriaCell")
 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

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top