Question

La question est simple: Comment vous chargez UITableViewCell personnalisé à partir des fichiers Xib? Cela vous permet d'utiliser Interface Builder pour concevoir vos cellules. La réponse est apparemment pas simple en raison de problèmes de mémoire managment. Ce fil mentionne la question et propose une solution, mais elle est avant NDA libération et manque code. Voici un qui traite de la question, sans donner une réponse définitive.

Voici un code que je l'ai utilisé:

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

Pour utiliser ce code, créez MyCell.m / .h, une nouvelle sous-classe de UITableViewCell et ajouter IBOutlets pour les composants que vous voulez. Ensuite, créez un nouveau fichier « vide XIB ». Ouvrez le fichier dans Xib IB, ajoutez un objet UITableViewCell, définissez son identifiant pour « MyCellIdentifier », et définir sa classe à MyCell et ajouter vos composants. Enfin, connectez le IBOutlets aux composants. Notez que nous ne l'avons pas mis propriétaire dans IB du fichier.

D'autres méthodes préconisent la mise du propriétaire du fichier et mettent en garde les fuites de mémoire si le Xib n'est pas chargé par une classe d'usine supplémentaire. Je l'ai testé ci-dessus en vertu des instruments / fuites et vu aucune fuite de mémoire.

Alors, quelle est la manière canonique pour charger les cellules de Xibs? Avons-nous mis propriétaire du fichier? Avons-nous besoin d'une usine? Si oui, quel est le code de l'usine ressemble? S'il y a plusieurs solutions, clarifions les avantages et les inconvénients de chacun d'eux ...

Était-ce utile?

La solution

Voici deux méthodes que le Etats auteur original a été recommandé par un ingénieur IB .

Voir le poste réel pour plus de détails. Je préfère la méthode 2 comme il semble plus simple.

Méthode n ° 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;
}

Méthode n ° 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;
}

Mise à jour (2014): Méthode n ° 2 est toujours valide, mais il n'y a pas de documentation pour plus. Auparavant, dans le docs officiels mais est maintenant supprimé en faveur de storyboards.

J'ai posté un exemple de travail sur Github:
https://github.com/bentford/NibTableCellExample

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

Autres conseils

La bonne solution est la suivante:

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

Inscription

Après iOS 7, ce processus a été simplifié jusqu'à ( rapide 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")
  

( Remarque ) Ceci est également possible en créant les cellules dans les fichiers .xib ou .stroyboard, comme des cellules prototypes.   Si vous devez joindre une classe à eux, vous pouvez sélectionner le prototype de cellule et ajouter la classe correspondante (doit être un descendant de UITableViewCell, bien sûr).

Dequeue

Et plus tard, à l'aide dequeued ( rapide 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 différence étant que cette nouvelle méthode dequeues non seulement la cellule, il crée également si inexistant (cela signifie que vous ne devez pas faire manigances if (cell == nil)), et la cellule est prête à l'emploi comme dans l'exemple ci-dessus.

  

( Avertissement ) tableView.dequeueReusableCell(withIdentifier:for:) a le nouveau comportement, si vous appelez l'autre (sans indexPath:) vous obtenez l'ancien comportement, dans lequel vous devez vérifier nil et par exemple vous iT, notez la UITableViewCell? valeur de retour.

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

Et bien sûr, le type de la classe associée de la cellule est celui défini dans le fichier .xib pour la sous-classe UITableViewCell, ou bien, en utilisant l'autre méthode de registre.

Configuration

Idéalement, vos cellules ont déjà été configurés en termes d'apparence et de positionnement de contenu (comme des étiquettes et des vues d'image) au moment où vous les avez enregistrés, et sur la méthode de cellForRowAtIndexPath vous les remplissez simplement.

Tous ensemble

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

Et bien sûr, tout cela est disponible en ObjC avec les mêmes noms.

A pris la réponse de Shawn Craver et nettoyé un peu.

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

Je fais toutes mes sous-classes de UITableViewCell de BBCell, puis remplacer la norme

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

avec:

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

je bentford de Méthode # 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;
}

Il fonctionne, mais attention pour les connexions à propriétaire dans votre fichier .xib UITableViewCell coutume de fichier.

En passant owner:self dans votre déclaration de loadNibNamed, vous définissez le UITableViewController en tant que propriétaire de votre UITableViewCell de fichier.

Si vous glissez et déposez le fichier d'en-tête dans le Bureau international de mettre en place des actions et des points de vente, il les mettre en place en tant que propriétaire de fichier par défaut.

En loadNibNamed:owner:options, le code d'Apple essayera de définir les propriétés de votre UITableViewController, puisque c'est le propriétaire. Mais vous n'avez pas ces propriétés définies là, vous obtenez une erreur d'être valeur de clé de codage conforme :

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

Si un événement se déclenche à la place, vous aurez 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

Une solution facile est de pointer vos connexions Interface Builder au UITableViewCell au lieu du propriétaire du fichier:

  1. Faites un clic droit sur le propriétaire du fichier pour tirer la liste des connexions
  2. Prenez une capture d'écran avec Commande-Maj-4 (faites glisser pour sélectionner la zone à capturer)
  3. x les connexions de propriétaire du fichier
  4. Faites un clic droit sur le UITableCell dans la hiérarchie d'objets et ajouter de nouveau les connexions.

J'ai décidé de poster depuis que je n'aime pas l'une de ces réponses - les choses peuvent toujours être plus simple et c'est de loin la façon la plus concise que j'ai trouvé

.

1. Construisez votre Xib dans Interface Builder comme vous l'aimez

  • Définir le propriétaire de fichier à la classe NSObject
  • Ajouter un UITableViewCell et définir sa classe à MyTableViewCellSubclass - si vos accidents IB (qui se passe dans Xcode> 4 de cette écriture), il suffit d'utiliser un UIView de faire l'interface dans Xcode 4 si vous avez encore autour de la pose
  • Mise en page vos sous-vues dans cette cellule et fixez vos connexions IBOutlet à votre @interface dans le .h ou .m (.m est ma préférence)

2. Dans votre UIViewController ou sous-classe 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. Dans votre MyTableViewCellSubclass

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

    return self;
}

Si vous utilisez Interface Builder pour faire des cellules, vérifiez que vous avez défini l'identificateur dans l'inspecteur. Ensuite, vérifiez qu'il est le même lors de l'appel dequeueReusableCellWithIdentifier.

J'ai oublié accidentellement de définir des identifiants dans un projet de table-lourd, et le changement de performance était comme la nuit et le jour.

UITableViewCells Chargement de XIBs permet d'économiser beaucoup de code, mais les résultats habituellement la vitesse de défilement horribles (en fait, ce n'est pas, mais l'utilisation XIB excessive de UIViews qui causent ce sujet).

Je vous suggère de jeter un oeil à ceci: Lien de référence

Voici la méthode de classe que je l'ai utilisé pour créer des cellules personnalisées sur 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;
}

Ensuite, dans le XIB, je mets le nom de classe et identifiant la réutilisation. Après cela, je peux appeler cette méthode dans mon contrôleur de vue au lieu de la balise

[[UITableViewCell] alloc] initWithFrame:]

Il y a beaucoup assez rapide, et utilisé dans deux de mes applications maritimes. Il est plus fiable que d'appeler [nib objectAtIndex:0], et dans mon esprit au moins, plus fiable que l'exemple de Stephan Burlot parce que vous êtes assuré de saisir seulement une vue d'un qui est le XIB bon type.

Solution correcte est la suivante

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

Rechargement la BNI est cher. Il vaut mieux charger une fois, puis instancier les objets lorsque vous avez besoin d'une cellule. Notez que vous pouvez ajouter UIImageViews etc à la pointe, même plusieurs cellules, en utilisant cette méthode ( « registerNIB » d'Apple iOS5 permet seulement un objet de niveau supérieur - Bug 10580062 "IOS5 tableView registerNib: trop restrictive"

Donc, mon code est ci-dessous - vous lisez dans la NIB une fois (en initialize comme je l'ai fait ou viewDidLoad -.. Tout A partir de là, vous instanciez la plume en objets choisir alors celui dont vous avez besoin Ceci est beaucoup plus efficace que le chargement de la pointe et encore.

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

Cochez cette - http://eppz.eu/blog/custom-uitableview-cell / - façon très pratique à l'aide d'une petite classe qui finit par une ligne dans la mise en œuvre du contrôleur:

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

entrer image description ici

La bonne façon de le faire est de créer une implémentation de la sous-classe UITableViewCell, en-tête et XIB. Dans le supprimer toutes les vues XIB et il suffit d'ajouter une cellule de table. Définissez la classe comme le nom de la sous-classe UITableViewCell. Pour le propriétaire du fichier, en faire le nom de la classe de sous-classe UITableViewController. Connectez le propriétaire du fichier à la cellule en utilisant la sortie tableViewCell.

Dans le fichier d'en-tête:

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

Dans le fichier de mise en œuvre:

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

Ce que je fais pour c'est déclarer un IBOutlet UITableViewCell *cell dans votre classe de contrôleur. Ensuite, invoquer la méthode de classe NSBundle loadNibNamed, qui alimentera la UITableViewCell à la cellule déclarée ci-dessus.

Pour la xib je vais créer un vide et ajouter xib l'objet UITableViewCell dans IB où il peut être configuré en fonction des besoins. Ce point de vue est alors relié à la IBOutlet cellulaire dans la classe du contrôleur.

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

additions NSBundle loadNibNamed (login ADC)

cocoawithlove.com article I provient du concept de (obtenir les numéros de téléphone échantillon app)

Tout d'abord importer votre fichier de cellule personnalisé #import "CustomCell.h" puis changer la méthode de délégué comme mentionné ci-dessous:

- (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. Créez votre propre sous-classe classe AbcViewCell personnalisée à partir UITableViewCell (Assurez-vous que votre nom de fichier de classe et le nom du fichier nib sont les mêmes)

  2. Créer cette méthode de classe d'extension.

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

    let cell: AbcViewCell = UITableViewCell.fromNib()

Swift 4.2 et Xcode 10

J'ai trois fichiers de cellules XIB

viewDidLoad enregistrer vos fichiers comme ça ... XIB

Cette première approche est

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

Approche deuxième registre directement des fichiers dans XIB cellForRowAt indexPath:

Ceci est mon fonctions de délégué de 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
    }

}

Voici ma méthode pour cela: Chargement personnalisé UITableViewCells de fichiers ... XIB Une autre méthode

L'idée est de créer une sous-classe SampleCell de la UITableViewCell avec une propriété IBOutlet UIView *content et une propriété pour chaque commande sous-vue vous devez configurer à partir du code. Ensuite, pour créer un fichier SampleCell.xib. Dans ce fichier nib, changer le propriétaire du fichier à SampleCell. Ajouter un UIView contenu de taille pour répondre à vos besoins. Ajouter et configurer tous les sous-vues (étiquette, vues d'image, boutons, etc.) que vous voulez. Enfin, relier la vue du contenu et les sous-vues au propriétaire du fichier.

Voici une approche universelle pour l'enregistrement des cellules dans 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)
    }
}

Explication:

  1. protocole génère Reusable ID de cellule de son nom de classe. Assurez-vous que vous suivez la convention:. cell ID == class name == nib name
  2. UITableViewCell conforme à Reusable protocole.
  3. extension UITableView fait abstraction de la différence dans l'enregistrement des cellules par nib ou classe.

Exemple d'utilisation:

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
}

Je ne sais pas s'il y a une façon canonique, mais voici ma méthode:

  • Créez un xib ViewController
  • Définissez la classe du propriétaire du fichier à UIViewController
  • Supprimer la vue et ajouter un UITableViewCell
  • Définissez la classe de votre UITableViewCell à votre classe personnalisée
  • Définissez l'identifiant de votre UITableViewCell
  • Régler la sortie de votre point de vue vue du contrôleur à votre UITableViewCell

En utilisant ce code:

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

Dans votre exemple, en utilisant

[nib objectAtIndex:0]

peut casser si Apple change l'ordre des éléments dans le 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;

Cette extension nécessite beta6 Xcode7

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

Créez un fichier Xib qui contient UITableViewCell seulement 1 sur commande.

Chargez.

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top