web-dev-qa-db-fra.com

La classe de registre UICollectionViewCell échoue, mais le nib de registre fonctionne

Créer une UICollectionViewCell personnalisée pour ma UICollectionViewController, cela fonctionne en enregistrant le nib; cependant, ne parvient pas à s'inscrire par classe.

Utilisation de registerClass () - échoue

L'enregistrement par classe semble correct - il est construit, mais lève une exception lors de l'exécution en décompressant les éléments optionnels de UIView. Sans référencer les points de vente, il fonctionne; cependant, aucune cellule n'apparaît dans la vue de collection. 

collectionView?.registerClass(MyCollectionViewCell.self, 
                              forCellWithReuseIdentifier: "myCell")

Clairement la vue n'est pas chargée; Cependant, je pense que la définition de la classe personnalisée de la cellule fournirait le lien nécessaire.

Utilisation de registerNib () - fonctionne

L'enregistrement par nib fonctionne, ce qui a du sens car il charge explicitement la vue.

let nib = UINib(nibName: "MyCollectionViewCell", bundle: nil)
collectionView?.registerNib(nib, forCellWithReuseIdentifier: "myCell")

Ici, la vue est explicitement référencée et une classe personnalisée est définie pour la vue; Cependant, quelque chose à ce sujet semble faux.

Exemple de projet

En isolant le problème dans un exemple de projet, vous trouverez ci-dessous les vues et le code à répliquer; ou, ce projet est disponible sur GitHub .

Main.storyboard

Mon contrôleur de vue initiale du storyboard principal est un UICollectionViewController sous-classé comme MyCollectionViewController:

 UICollectionViewController

MyCollectionViewController.Swift

Affichage des inscriptions par nib et par classe:

import UIKit

class MyCollectionViewController: UICollectionViewController {

    var data = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        data = ["a", "b", "c"]

        // This works, by nib
        let nib = UINib(nibName: "MyCollectionViewCell", bundle: nil)
        collectionView?.registerNib(nib, forCellWithReuseIdentifier: "myCell")

        // This fails, by class
        //collectionView?.registerClass(MyCollectionViewCell.self, forCellWithReuseIdentifier: "myCell")
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("myCell", forIndexPath: indexPath) as! MyCollectionViewCell

        cell.title.text = data[indexPath.row]

        return cell
    }

}

MyCollectionViewCell.xib 

La vue est une UICollectionViewCell subdivisée en MyCollectionViewCell avec une UILabel:

 MyCollectionViewCell

Dans ma nib, l'identifiant identificateur de vue de collection réutilisable a été défini sur: myCell:

 MyCollectionViewCell-identifier

MyCollectionViewCell.Swift

Définit la classe et a une variable IBOutlet à l'étiquette:

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var title: UILabel!

}

En utilisant le nib, l'exécution apparaît comme:

 iphone-4s

Pourquoi ne puis-je pas enregistrer UICollectionViewCell par classe?

De plus, je suis un peu confus quant à savoir si la cellule prototype doit rester sur le contrôleur de vue de la collection de storyboard principale. Là, je n’ai défini aucun identifiant de vue réutilisable.

12
Jason Sturges

Je vois ce lien Vue d'ensemble de la collection

Si la classe de cellules a été écrite en code, l'enregistrement est effectué à l'aide de la méthode registerClass: de UICollectionView. Par exemple: [self.myCollectionView registerClass: [MyCollectionViewCell class] pourCellWithReuseIdentifier: @ "MYCELL"]; Si la cellule est contenue dans un fichier NIB d'Interface Builder, la méthode registerNib: est utilisée à la place.

Donc, votre cellule de collecte crée avec nib, vous devez vous inscrire avec nib. Si votre cellule est totalement écrite en code, vous devrez vous inscrire auprès de la classe.

J'espère que cette aide.

16
vien vu

En fait, si vous enregistrez la classe dans le scénario et lui attribuez un identifiant de réutilisation, vous ne devriez pas enregistrer sa classe ou sa nib en code. 

2
pbush25

si vous définissez une cellule à partir d'un fichier NIB, le système choisira le fichier NIB pour instancier la cellule. Si vous ne définissez aucun fichier nib (totalement géré par le code), la cellule doit être initiée par le 

- initWithStyle:reuseIdentifier:

méthode . Lorsque vous utilisez

- dequeueReusableCellWithIdentifier:

la méthode - awakeFromNib sera appelée si vous utilisez nib pour conserver la vue; else 

- initWithStyle:reuseIdentifier:

sera appelé.

1
musixlemon

Ce n'est pas collectionview qui échoue ici. Votre classe personnalisée contient une étiquette implicitement non emballée, définie comme ceci,

@IBOutlet weak var title: UILabel!

Et c'est la raison de l'échec. Où l'instanciez-vous? Et vos méthodes de sources de données sont appelées ce qui est comme ça,

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("myCell", forIndexPath: indexPath) as! MyCollectionViewCell

    cell.title.text = data[indexPath.row]

    return cell
}

Là, vous essayez de définir du texte sur cette propriété titre qui est nul, ce qui bloque votre application. 

Initialisez votre étiquette dans collectionView initWithFrame: method si vous l’utilisez dans un code qui devrait être corrigé.

Ajoutez ce code à votre sous-classe de cellules lors de l'utilisation de in code,

class MyCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var title: UILabel!

    override init(frame: CGRect) {
        super.init(frame: frame)
        let title = UILabel(frame: CGRectZero)
        title.translatesAutoresizingMaskIntoConstraints = false;
        contentView.addSubview(title)
        self.title = title

        title.topAnchor.constraintEqualToAnchor(contentView.topAnchor).active = true
        title.leftAnchor.constraintEqualToAnchor(contentView.leftAnchor).active = true
        self.backgroundColor = UIColor.redColor()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
1
Sandeep