[SWIFT 3] CollectionView et contrainte

2»

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur

    Bah quand j'ai mis le code dans viewDidLoad, ça ne fonctionnait pas, je passais même pas dedans O_o




    Oups ! Je voulais dire awakeFromNib ;)
  • InsouInsou Membre
    juin 2017 modifié #33


    J'ai changé les UITextViews pour les UILabels mais l'idée est pareille


     


    attachicon.gifCollectionCell.png




     


    Je reviens sur ça..


     


    Je dois ajouter des images dans mes messages du coup je me suis dit que c'était l'occasion de tester via le storyboard, j'ai créé une nouvelle cellule (identifier : Cell_image) qui utilise la classe ChatLogMessageSortantImageCollectionViewCell



    class ChatLogMessageSortantImageCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var ImageView: UIImageView!
    @IBOutlet weak var messageLabel: UILabel!

    }

    Elle contient une image et un label.


     


    Dans ma classe DiscussionsCollectionViewController, j'ai ça :



    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{

    ...

    // Si il y a une image
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell_image", for: indexPath) as? ChatLogMessageSortantImageCollectionViewCell{
    cell.messageLabel.text = Message // ERREUR ICI
    ... // la suite du code est pour changer l'image aussi mais j'ai la même erreur
    }

    }

    Et je me retrouve donc avec une erreur : fatal error: unexpectedly found nil while unwrapping an Optional value


     


    Ma variable "Message" est bien rempli, je l'affiche bien dans ma console donc le soucis ne vient pas de là .


    Dans le debugger, je regarde dans cell >> ImageView et j'ai nil


    Je pense que le soucis vient de là  mais je n'arrive pas à  comprendre pourquoi..


    Où est ce que j'ai oublié un truc ?


     


    De ce que je comprends, pour moi il sait bien qu'il doit utiliser la cellule de la classe ChatLogMessageSortantImageCollectionViewCell


    Donc il a accès à  ces "éléments" (l'image et le label), en plus il me les propose dans l'auto-complétion, du coup je ne comprends pas pourquoi il ne le retrouve pas quand il passe dedans :/


  • LarmeLarme Membre
    juin 2017 modifié #34

    Dans le storyboard, tu as lié le messageLabel et/ou ImageView avec la classe côté code (IBOulet) ?


  • Oui oui, ils sont reliés dans la classe ChatLogMessageSortantImageCollectionViewCell

  • Joanna CarterJoanna Carter Membre, Modérateur

    Il y a une bulle noire à  gauche de l'IBOutlet dans le code ?


  • Oui :)


     


  • En testant si la cellule se créée bien, je me rend compte que non..



    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell_image", for: indexPath) as? ChatLogMessageSortantImageCollectionViewCell{
    print("##########")
    print(Message)
    print(" ")
    if let messageLabel = cell.messageLabel {
    print("okok?")
    messageLabel.text = Message
    }
    else{
    print("pas okok")
    }

    return cell
    }

    il n'y a pas un truc qui peut me dire pourquoi ma cellule ne se créée pas ?


  • Joanna CarterJoanna Carter Membre, Modérateur

    1. T'as créé un UIViewController dans un storyboard ?


    2. Tu l'as désigné la classe DiscussionCollectionViewController ?


    3. T'as créé la cellule dans la CollectionView ?


    4. Tu l'as désigné la classe ChatLogMessageCollectionViewCell ?


    5. Tu l'as désigné l'identifiant Cell_image ?


  • 1/ Oui


    2/ Oui


    3/ Dans ma CollectionView, j'ai 2 cellules :


    - Une qui utilise ChatLogMessageCollectionViewCell pour créer les bulles + message (identifiant : "Cell")


    - Une qui utilise ChatLogMessageSortantImageCollectionViewCell pour créer les bulles + message + image (identifiant : "Cell_image")


     


    Dans ma fonction, je fais le test pour savoir si il y a une image, si c'est le cas, j'utilise la cellule avec image, si il n'y en a pas, j'utilise la cellule sans image..


     


    4/ Du coup, c'est ChatLogMessageSortantImageCollectionViewCell que je dois utiliser comme classe et oui, c'est celle qui est utilisée sur ma cellule avec image


    5/ Oui


  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu appelles collectionView.register(...) pour les classes de cellules ?


     


    Si oui, il ne faut pas le faire car les cellules sont déjà  enregistrées à  cause de leurs placement dans la CollectionView.


     


    Tu peux nous montrer un capture d'écran pour une des cellules dans la vue, avec l'inspecteur qui affiche ses propriétés ?


  • InsouInsou Membre
    juin 2017 modifié #42

    Si j'enleve :



    myCollectionViewMessage?.register(ChatLogMessageSortantImageCollectionViewCell.self, forCellWithReuseIdentifier: "Cell_image")

    Alors je me retrouve avec l'erreur :


     



    init(coder:) has not been implemented



     


    de ma classe ChatLogMessageSortantImageCollectionViewCell :



    class ChatLogMessageSortantImageCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var ImageView: UIImageView!
    @IBOutlet weak var messageLabel: UILabel!

    override init(frame: CGRect) {
    super.init(frame: frame)
    print("ok init")
    }

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

    }

    Captures d'écrans : 


     


    1.png 152.9K
    2.png 47.6K
  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu n'as pas nous montré l'Identity Inspector (prochain à  gauche de l'Attributes Inspector) pour la cellule.


  • Bah c'est pas mon 2eme screen ? :/


  • Joanna CarterJoanna Carter Membre, Modérateur

    Oups ! Tu vends les lunettes ?  8--)


  • Joanna CarterJoanna Carter Membre, Modérateur

    Voici mon code :



    class TestCell: UICollectionViewCell
    {
    @IBOutlet weak var ImageView: UIImageView!

    @IBOutlet weak var messageLabel: UILabel!
    }


    class TestController: UICollectionViewController
    {
    override func viewDidLoad()
    {
    super.viewDidLoad()

    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
    return 3
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? TestCell else
    {
    fatalError()
    }

    cell.messageLabel.text = "fred"

    return cell
    }
    }

    Et, côté cellules, c'est tout ce qu'il faut.


     


    Mais je viens de noter que tu as :



    override init(frame: CGRect) {
    super.init(frame: frame)
    print("ok init")
    }

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

    ... dans ta classe cellule. Tu n'as pas besoin de ni l'une ni l'autre de ces méthodes.


  • Joanna CarterJoanna Carter Membre, Modérateur

    Ou, pour deux types de cellules différents :



    class TestCell: UICollectionViewCell
    {
    @IBOutlet weak var messageLabel: UILabel!
    }


    class TestImageCell: UICollectionViewCell
    {
    @IBOutlet weak var imageView: UIImageView!

    @IBOutlet weak var messageLabel: UILabel!
    }


    class TestController: UICollectionViewController
    {
    override func viewDidLoad()
    {
    super.viewDidLoad()

    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
    return 3
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
    var reuseIdentifier: String

    switch indexPath.item
    {
    case 0:
    reuseIdentifier = "Cell"
    default:
    reuseIdentifier = "ImageCell"
    }


    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as UICollectionViewCell? else
    {
    fatalError("could not find cell")
    }

    switch cell
    {
    case let testCell as TestCell:
    testCell.messageLabel.text = "normal"
    case let testImageCell as TestImageCell:
    testImageCell.messageLabel.text = "image"
    testImageCell.imageView.image = nil
    default:
    break
    }

    return cell
    }
    }

    Et, pour le storyboard :


     


  • J'ai refais un projet pour tester ton code.. ça fonctionne bien, pas de soucis.


     


    J'ai comparé avec mon code et j'ai pourtant la même chose.. mais ma variable "messageLabel" est à  nil dans le debugger, comme si il faisait pas le lien.. qu'il ne retrouvait pas la cellule via son identifiant :/


  • Joanna CarterJoanna Carter Membre, Modérateur

    Mon conseil, c'est de revisiter le storyboard et revérifier que tous les outlets sont bien liés.


     


    Ctrl-click sur chaque label, imageView, etc et là  tu trouveras la liste des connexions.


  • Bon bah j'ai supprimé la cellule et les outlets, j'ai recréer la cellule, changé tout les noms des outlets en les re-créant, changé l'identifiant de la cellule aussi et là  j'ai plus l'erreur ^^


    J'sais pas vraiment ce qu'il s'est passé pour que ça fonctionne mais bon.. Xcode s'est peut être emmêlé les pinceaux à  un moment donné :s


     


    Merci de ta patience Joanna :D


  • Joanna CarterJoanna Carter Membre, Modérateur

    De rien. Avec plusieurs ans d'expérience de Xcode, rien ne m'étonnerait pas.


     


    Mais, attention lorsque tu travail avec les storyboards ; c'est très/trop facile à  taper/supprimer qqch. inattendu.


Connectez-vous ou Inscrivez-vous pour répondre.