1 ViewController gérant 2 tableView

Bonjour,

Je cherche sur une ViewController à gérer 2 Table View.
Mais j’ai un problème dans mon code pour la déclaration de la cellule cell.
Xcode me dit que j’ai une erreur à cet endroit et l’application plante.

Alors, le context : je pars d’une TableViewController. je clique sur une ligne et au lieu de m’afficher la ViewController suivante qui gère les 2 tableView, l’application plante…

Je mets le bout de code qui pose problème :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    var cell:UITableViewCell?

    
    if tableView == tableView1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)
        let aItem = aArray[indexPath.row]
        cell.textLabel?.text = aItem.title
        titleLabel?.text = selectedCat?.title
    }

    
    else if tableView == tableView2 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath)
        let rItem = rArray[indexPath.row]
        cell.textLabel?.text = rItem.title
        titleLabel?.text = selectedCat?.title
    }
    return cell!
}

Quand je l’intègre à mon code, Xcode me dit que « cell » ne change jamais de valeur et me retourne une erreur sérieuse (app crash) sur la ligne « return cell! ».

Pourquoi ? Qu’est ce que j’ai oublié de faire ?

Je comprends bien que quand je clique sur une catégorie précédente et que j’attends qu’il m’ouvre la ViewController suivante, avec deux table View en attente, je comprends qu’il lui manque une valeur par défaut de cell, mais je ne peux pas fixer la valeur de cell à cell1, par exemple… quand j’écrirai dans la tableView2, je risque d’avoir une autre erreur…

Merci de votre aide.

laminwdpro

Salut @laminwdpro,

Supprime le “let” devant “cell” dans tes if. :slight_smile:

Merci. Mais pourquoi le let bloquait ? ne devrais-je pas mettre le let ou var pour déclarer la variable ?
Merci de ta réponse.

Tu déclares cell en tant que var avant ton ta condition puis tu essayes de redéclaré cell ce qui est interdit. Une fois une variable déclaré à l’aide d’un var ou d’un let tu n’as pas le droit de la redéclarer.

Pour faire simple une variable tu la déclares avec un var ou un let puis tu l’utilise directement (sans var ou let devant).
var permet de la modifier à volonté
let ne permet pas de la modifier. Une fois défini la variable ne peut être modifier.

Je te conseille de te renseigner sur la porté des variables, pour plus d’explication.

Samir a raison, en supprimant le let devant cell, tu régleras le bug. La question est de savoir pourquoi.

Il y a deux problèmes dans ton code : un masquage de variable et une conversion à la hussarde d’une variable optionnelle nulle.


Quand tu crée une variable dans un bloc d’instructions, elle n’existe qu’à l’intérieur de ce bloc. C’est ce qu’on appelle la portée de la variable. Les limites sont définies par les symboles { et }.

Exemple : je crée une fonction faireUnTruc(), avec une variable var1.

func faireUnTruc() {
        
        // Création de la variable var1
        let var1 = 12
        print ("var1 au début de la fonction : ", var1)

        // Faire quelque chose
        // .....
       
        print ("var1 à la fin de la fonction : ", var1)
    }

var1 n’existe que dans l’espace délimité par les symboles { } situés après le nom de la fonction.

Je peux placer un autre bloc d’instruction à l’intérieur de la fonction, une boucle ou un simple test. Les variables créées dans ce bloc n’existeront que dans celui-ci et seront invisibles pour le reste de la fonction. C’est par exemple le cas d’une boucle, l’indice de celle-ci n’est pas accessible dans le reste de la fonction. C’est très pratique.

Il y a cependant un gros problème. On peux créer de nouvelles variables dans le bloc d’instruction, Y COMPRIS DU MEME NOM QU’UNE AUTRE VARIABLE DE LA FONCTION !

if tableView == tableView1 {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)
    let aItem = aArray[indexPath.row]
    cell.textLabel?.text = aItem.title
    titleLabel?.text = selectedCat?.title
}

Quand tu tape let cell = tableView.quelquechose, tu CREES UNE NOUVELLE VARIABLE CELL, qui n’existe que dans le bloc d’instruction local, défini par les { } du test if tableView == tableView1.

Tu crois modifier le contenu de la variable var1 défini au début, mais en fait tu accède à son jumeau maléfique portant le même nom, mais n’existant que de manière fugitive. C’est un phénomène de masquage.

Xcode te prévient que cell ne change jamais de valeur, parce que c’est précisément le cas !

En retirant le let de la formule let cell = … tu empêche la création d’une nouvelle variable et indique à Xcode qu’il doit utiliser la variable définie au début de la fonction.

J’ai écrit une autre version de la fonction faireUnTruc() pour mettre le phénomène en évidence. J’ai juste rajouté un test bidon pour créer un nouveau bloc d’instruction, et une nouvelle variable var1.

func faireUnTruc() {
        
        // Création de la variable var1
        let var1 = 12
        print ("var1 au début de la fonction : ", var1)
        
        // Bloc d'instructions
        if true {
            // Création d'une NOUVELLE variable var1
            let var1 = 749
            print ("var1 dans le bloc d'instructions : ",var1)
        }
            
        print ("var1 à la fin de la fonction : ", var1)
    }

Après exécution, cela donne :

var1 au début de la fonction : 12
var1 dans le bloc d’instructions : 749
var1 à la fin de la fonction : 12

On voit bien qu’il y a eu création d’une nouvelle variable var1, avec un contenu différent de sa soeur jumelle.

Le masquage est potentiellement dangereux. Il faut faire attention à l’éviter.


2 « J'aime »

Le plantage vient de ta mauvaise utilisation de la variable cell. Comme je l’ai expliqué dans le post précédent, tu ne modifies jamais son contenu.

C’est une variable optionnelle, donc Xcode l’initialise automatiquement avec la valeur nill (nulle, ne contient rien).

Tu termines ta fonction par le code

return cell!

L’opérateur ! a pour tâche de convertir une variable optionnelle en une variable normale, contenant forcément une information. L’ennui c’est que cell ne contient aucune information, puisque rien n’a été écrit dedans. Puisque swift ne peut pas inventer quelque chose qu’il ne connait pas, il préfère planter ce qui arrête l’exécution de l’application.

Merci à tous pour vos réponses. Elles sont fort appréciables. Ainsi que les explications détaillées.
Au plaisir de vous lire de nouveau.

laminwdpro.