UITableView et recyclage des cellules

TerflogagTerflogag Membre
octobre 2015 modifié dans API UIKit #1

Bonsoir,


 


Je viens vers vous avez un soucis assez simple : je dispose d'un UITableViewController avec des UITableViewCell contenant chacune un UITextField. Lorsque je scroll, le contenu du textfield de certaines cellule apparait plus haut ou plus bas. 


Après avoir creusé il s'agirait d'un soucis de réutilisation de mes cellules, plusieurs solutions apparaissent : 


- travailler avec indexPath.row et un tableau contenant mes données a y mettre (chose que je fais déjà )


- création d'une UITableViewCell a chaque passage : solution non viable et pas du tout adéquat...


 


La premiere solution est déjà  mise en oeuvre dans mon cas : j'ai trois tableaux de données, un par section.


 


Voici un échantillon de mon code (avec l'essentiel) : 



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCellWithIdentifier("matCell", forIndexPath: indexPath) as! MatiereTableViewCell
        
        
        switch (indexPath.section) {
        case 0:
            cell.textLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].nom
            cell.detailTextLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].getCoefString()
            cell.imputLabel.tag = 100 + indexPath.row
            cell.tag = 100 + indexPath.row
            cell.imputLabel.delegate = self
 
            if self.listeMatAnticip?.listeMat[indexPath.row].note != 0 {
                cell.imputLabel.text = "\((self.listeMatAnticip?.listeMat[indexPath.row].note)!)"
            }
            break
        case 1:
            cell.textLabel?.text = self.listeMatTerminale?.listeMat[indexPath.row].nom
            cell.detailTextLabel?.text = self.listeMatTerminale?.listeMat[indexPath.row].getCoefString()
            cell.imputLabel.tag = 200 + indexPath.row
            cell.tag = 200 + indexPath.row
            cell.imputLabel.delegate = self

            if self.listeMatTerminale?.listeMat[indexPath.row].note != 0 {
                cell.imputLabel.text = "\((self.listeMatTerminale?.listeMat[indexPath.row].note)!)"
            }
            break
        case 2:
            cell.textLabel?.text = self.listeMatOption?.listeMat[indexPath.row].nom
            cell.detailTextLabel?.text = self.listeMatOption?.listeMat[indexPath.row].getCoefString()
            cell.imputLabel.tag = 300 + indexPath.row
            cell.tag = 300 + indexPath.row
            cell.imputLabel.delegate = self

            if self.listeMatOption?.listeMat[indexPath.row].note != 0 {
                cell.imputLabel.text = "\((self.listeMatOption?.listeMat[indexPath.row].note)!)"
            }
            break
        default:
            break
        }
        
        //print("matiere : \(cell.textLabel?.text) et note : \((cell.imputLabel.text)!)")
        
        return cell
    }

J'ai tenté de nombreuse chose, mais c'est ma premiere application en Swift et je me perd également avec les types optionnel, une vrai galère pour l'instant...


 


Bonne soirée 


 


EDIT : Si mon code vous paraà®t inapproprié ou sale n'hésitez pas, je suis preneur de toutes vos remarques.


Réponses

  • AliGatorAliGator Membre, Modérateur
    octobre 2015 modifié #2
    Que de duplication de code !

    - Tu peux enlever les "break", inutiles en Swift dans un switch/case
    - Tu devrais aussi à  priori factoriser un peu ton code, les 3 case ont l'air de se ressembler fortement.
    - Et sinon, je t'invite à  arrêter de tuer des poneys (je déconseille fortement l'utilisation des "!" à  part si c'est vraiment justifié et bien réfléchi, mais là  c'est pas justifié dans ton cas)
  • RomheinRomhein Membre
    octobre 2015 modifié #3

    oui au niveau factorisation tu peux faire un truc quand même !


     


    par exemple :



    cell.textLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].nom
    cell.detailTextLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].getCoefString()
    cell.imputLabel.tag =(indexPath.section+1)*100 + indexPath.row
    cell.tag = (indexPath.section+1)*100 + indexPath.row
    cell.imputLabel.delegate = self

    if self.listeMatAnticip?.listeMat[indexPath.row].note != 0 {
    cell.imputLabel.text = "\((self.listeMatAnticip?.listeMat[indexPath.row].note)!)"
    }

  • TerflogagTerflogag Membre
    octobre 2015 modifié #4

    Que de duplication de code !

    - Tu peux enlever les "break", inutiles en Swift dans un switch/case
    - Tu devrais aussi à  priori factoriser un peu ton code, les 3 case ont l'air de se ressembler fortement.
    - Et sinon, je t'invite à  arrêter de tuer des poneys (je déconseille fortement l'utilisation des "!" à  part si c'est vraiment justifié et bien réfléchi, mais là  c'est pas justifié dans ton cas)

     
    Merci pour le lien, très instructif, beau boulot !
     

    oui au niveau factorisation tu peux faire un truc quand même !
     
    par exemple :

    cell.textLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].nom
    cell.detailTextLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].getCoefString()
    cell.imputLabel.tag =(indexPath.section+1)*100 + indexPath.row
    cell.tag = (indexPath.section+1)*100 + indexPath.row
    cell.imputLabel.delegate = self

    if self.listeMatAnticip?.listeMat[indexPath.row].note != 0 {
    cell.imputLabel.text = "\((self.listeMatAnticip?.listeMat[indexPath.row].note)!)"
    }

     
     
    Effectivement le code se ressemble mais dans chacun des cas (pour chaque section) il y a une source différente. A moins de rassemble ces 3 sources dans un 4 eme tableau dans lequel je viens piocher avec indexPath.section... 
     
    En facto' et en sauvant 3 poneys cela donne ceci :
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("matCell", forIndexPath: indexPath) as! MatiereTableViewCell
            
            cell.imputLabel.text = ""

            switch (indexPath.section) {
            case 0:
                cell.textLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].nom
                cell.detailTextLabel?.text = self.listeMatAnticip?.listeMat[indexPath.row].getCoefString()
            
                if let note = self.listeMatAnticip?.listeMat[indexPath.row].note {
                    if note != 0 {
                        cell.imputLabel.text = "\(note)"
                    }
                }
            case 1:
                cell.textLabel?.text = self.listeMatTerminale?.listeMat[indexPath.row].nom
                cell.detailTextLabel?.text = self.listeMatTerminale?.listeMat[indexPath.row].getCoefString()
                
                if let note = self.listeMatTerminale?.listeMat[indexPath.row].note {
                    if note != 0 {
                        cell.imputLabel.text = "\(note)"
                    }
                }

            default:
                cell.textLabel?.text = self.listeMatOption?.listeMat[indexPath.row].nom
                cell.detailTextLabel?.text = self.listeMatOption?.listeMat[indexPath.row].getCoefString()
           
                if let note = self.listeMatOption?.listeMat[indexPath.row].note {
                    if note != 0 {
                        cell.imputLabel.text = "\(note)"
                    }
                }
            }
            
            cell.tag = 100 + (100 * indexPath.section) + indexPath.row
            cell.imputLabel.tag = 100 + (100 * indexPath.section) + indexPath.row
            cell.imputLabel.delegate = self
            
            return cell

        }
    EDIT : Problème résolu, j'avais oublié d'initialiser avec une chaine vide.. Donc si la cellule était réutilisé il pouvait y avoir tout de meme une valeur d'après ce que j'en comprend.
  • Tout rassembler dans un autre tableau te faciliterait énormément le code, dont juste la source change.

    À la limite, tu peux garder un switch case au début, avec un truc du genre (en Objective-C):



    NSArray *listeMat;
    switch ([indexPath section])
        case 0: 
            listeMat = self.listeMatAnticip.listeMat;
            break;
     etc.

    Voire, pour éviter d'avoir 36 trucs à  rallonge:



    TonObject *tonObjet;
    tonObjet = self.listeMatAnticip.listeMat[[indexPath row]];
  • AliGatorAliGator Membre, Modérateur
    octobre 2015 modifié #6

    En facto' et en sauvant 3 poneys cela donne ceci :

    ...
    if let note = self.listeMatAnticip?.listeMat[indexPath.row].note {
    if note != 0 {
    cell.imputLabel.text = "\(note)"
    }
    }

    Tu peux éviter les cascades d'indentation (dites "Pyramid of Doom") avec un "where":
    ...
    if let note = self.listeMatAnticip?.listeMat[indexPath.row].note where note != 0 {
    cell.imputLabel.text = "\(note)"
    }
    Bon et du coup avec un " else { cell.imputLabel.text = "" } " dans le cas contraire pour être sûr que même en cas de réutilisation d'une ancienne cellule ça remette les choses au propre, mais ça tu l'as apparemment déjà  corrigé d'après ton "EDIT".

    PS : En bon anglais ça s'écrit "inputLabel" et pas "imputLabel" ;)
  • CéroceCéroce Membre, Modérateur


    PS : En bon anglais ça s'écrit "inputLabel" et pas "imputLabel" ;)




    C'est de l'anglais du sud !

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