Swift, plist, Dictionnary et UITableView

Bonjour,


 


J'ai commencé un petit projet basique pour essayer de tater du Swift, d'apprendre le langage, de voir comment l'utiliser avec Cocoa Touch, etc...


 


Et bien je ne suis pas déçu : je galère grave !!! 


 


J'ai un fichier plist de type : 



<array>
<dict>
<key>clubName</key>
<string>Mickey</string>
</dict>
<dict>
<key>clubName</key>
<string>Pluto</string>
</dict>
</array>

Je lis le fichier de la manière suivante :



override func awakeFromNib() {
        super.awakeFromNib()
        
        let path = NSBundle.mainBundle().pathForResource("Clubs", ofType:"plist")
        clubsList = NSArray(contentsOfFile:path!)
        
        println(clubsList);
    }

Et je fais le UITableViewCell de la manière suivante :



override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        
        // Get a Cell
        let cell = tableView.dequeueReusableCellWithIdentifier("cellClub", forIndexPath: indexPath) as UITableViewCell
        
        let currentClub = clubsList.objectAtIndex(indexPath.row) as NSDictionary
        cell.textLabel.text = currentClub.valueForKey("clubName") as String
        

        // return the cell
        return cell
    }

Et ca plante à  l'éxecution sur la ligne :



cell.textLabel.text = currentClub.valueForKey("clubName") as String

J'ai essayer de passer par un Dictionnary au lieu d'un NSDictionnary mais je n'y suis pas arrivé non plus



 


Donc pour le moment Swift est un joli jouet dans le playground mais pour réaliser un projet (même basique) c'est pas jouable. Soit le langage n'est pas vraiment prêt soit c'est moi qui ne suit pas prêt (ou les deux)


 


Une idée pour résoudre ce cas ? 


(ou un exemple de code)


 


Merci d'avance.


«1

Réponses

  • Salut,


     


    ton println() t'affiche bien les informations stockées dans ton fichier plist ?


     


    Sinon pour moi, comme ça et après le peu d'expériences que j'ai sur le sujet, ça ressemble à  un problème 'optional'. En gros si une valeur est nulle ou absente il te sort l'erreur. 


     


    Si tu essayes d'afficher ton dictionnaire dans un println() par exemple, qu'est ce qu'il te renvoi ?


  • Alors :


    1. Le println(clubsList); me liste bien  le contenu de mon plist
    2. Et un println(currentClub) après le let currentClub = clubsList.objectAtIndex(indexPath.row) as NSDictionary m'affiche bien le dictionnaire correspondant a l'indexpath.row

       

    Visiblement ca plante sur le  cell.textLabel.text = currentClub.valueForKey("clubName") as String


  • Joanna CarterJoanna Carter Membre, Modérateur

    Si valueForKey renvoie nil, ça peut planter


  • @joanna : le  println(currentClub)  affiche bien une valeur pour la clé "clubName"



    {

        clubName = "Mickey";
    }
  • Hum on progresse, un println(currentClub.valueForKey("clubName")) renvoi : 



    Optional(Mickey)

    Et 



    println(currentClub.valueForKey("clubName") as String)
    println(currentClub.valueForKey("clubName") as NSString)

    plantent à  l'exécution


     


    Faut que je me documente sur les Optional j'ai du raté un truc à  ce niveau. Mais quoi ?


  • un "?" à  la fin devrait résoudre le problème en le marquant comme valeur optionnelle.




  • un "?" à  la fin devrait résoudre le problème en le marquant comme valeur optionnelle.




    Ou ça ?



    var clubName : String = currentClub.valueForKey("clubName") as String
    println(clubName)
    cell.textLabel.text = clubName

    Ca plante sur la première ligne. Je ne vois pas où mettre le "?"


    D'autant que où que ce soit que j'essaye de le mettre, ça ne build pas.

  • Si je fait :


     


    var clubName : String? = currentClub.valueForKey("clubName")?.string


    println(clubName)


    cell.textLabel.text = clubName


     


    J'ai clubName qui est nil !



  • let str: String? = NSBundle.mainBundle().pathForResource("Test", ofType: "plist")
    let clubsList = NSArray(contentsOfFile: str!)

    println(clubsList)

    let currentClub: AnyObject! = clubsList.objectAtIndex(0)

    var clubName : String? = currentClub.valueForKey("clubName") as? String
    println(clubName!) 

    Oui ça confirme le crash que tu avais.


     

    Je viens tout juste de tester la lecture d'un plist en reprenant un peu ce que tu as fais et normalement tout devrait fonctionner si le fichier est bien rempli. Le code est ci-dessus.


  • Paisible.frPaisible.fr Membre
    août 2014 modifié #11

    J'ai mis le code ci-dessous :


     


            let str: String? = NSBundle.mainBundle().pathForResource("Clubs", ofType: "plist")


            let clubsList = NSArray(contentsOfFile: str!)


            println(clubsList)


            


            let currentClub: AnyObject!  = clubsList.objectAtIndex(indexPath.row)


            println(currentClub)


            


            var clubName : String? = currentClub.valueForKey("clubName") as? String


            println(clubName!)


     


    Ca plante sur le println(clubName!) avec un  : fatal error: unexpectedly found nil while unwrapping an Optional value


     


    Je précise que println(clubsList) renvoie bien le tableau de clubs.


    Et que le println(currentClub) renvoie bien un club


     


    Le plist utilisé :


    <?xml version="1.0" encoding="UTF-8"?>


    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">


    <plist version="1.0">


    <array>


        <dict>


             <key>clubName</key>


             <string>Mickey</string>


        </dict>


        <dict>


            <key>clubName</key>


            <string>Plutot</string>


        </dict>


        <dict>


            <key>clubName</key>


            <string>Donald</string>


        </dict>


    </array>


    </plist>


     


    L'output de la console :


     


    2014-08-19 22:20:40.925 AUG France[5452:941265] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize=13.000000


    (


            {


            clubName = Mickey;


        },


            {


            clubName = Plutot;


        },


            {


            clubName = Donald;


        }


    )


    {


        clubName = Mickey;


    }


    fatal error: unexpectedly found nil while unwrapping an Optional value


    (lldb)


     


    Je me demande si cela ne vient pas des keys/values du dictionnaire.


    La value n'a pas de quotes !!!


  • Pour moi ton plist semble correct.


     


    Pour éviter un crash, ce que tu peux faire est la chose suivante :



    if let club = clubName {
    println(club)
    }


  •  


    Pour moi ton plist semble correct.


     


    Pour éviter un crash, ce que tu peux faire est la chose suivante :



    if let club = clubName {
    println(club)
    }



    OK ca évite le crash mais j'ai jamais ma valeur !


    Donc ça m'avance pas beaucoup  :'(

  • MagiicMagiic Membre
    août 2014 modifié #14

    en fait j'ai rien dit, j'ai sauté une ligne ! 


     


    Je sais pas et c'est vraiment bizarre à  vrai dire puisque à  un dictionary près j'ai la même chose que toi. La seule différence notable également c'est que je récupère que la première valeur pour tester. Peut être essayer le code ailleurs que ta méthode cellForRowAtIndexPath. 


  • Paisible.frPaisible.fr Membre
    août 2014 modifié #15

    Même soucis si je prend le premier élément avec le code source dans le AwakeFromNib


     


     override func awakeFromNib() {


            super.awakeFromNib()


            


            let str: String? = NSBundle.mainBundle().pathForResource("Clubs", ofType: "plist")


            let clubsList = NSArray(contentsOfFile: str!)


            println(clubsList)


            


            let currentClub: AnyObject!  = clubsList.objectAtIndex(0)


            println(currentClub)


            println(currentClub.dynamicType)


            


            var clubName : String? = currentClub.valueForKey("clubName") as? String


            println(clubName as String?)


            


            if let club = clubName {


                println(club)


            }


        }


     


     


    Ca me donne en sortie : 



    (
            {
            clubName = Mickey;
        },
            {
            clubName = Plutot;
        },
            {
            clubName = Donald;
        }
    )
    {
        clubName = Mickey;
    }
    (Metatype)
    nil

    Je n'y comprends vraiment plus rien


  • Je ne pense pas que cela ai un impact quelconque mais à  toute fin utilise je précise que je tourne sous :


    • OS X 10.9.4
    • Xcode Version 6.0 beta 6 (6A280e)
    • iOS Simulator iPhone 5 
  • Paisible.frPaisible.fr Membre
    août 2014 modifié #17

    J'ai essayé autre chose :


     


            var clubsList = []


            var currentClub : AnyObject


            var clubName: AnyObject?


            


            // Get the clubs list


            let path: String? = NSBundle.mainBundle().pathForResource("Clubs", ofType: "plist")


            clubsList = NSArray(contentsOfFile: path!)


            println(clubsList)


            


            // Get the informations of the 1st club


            currentClub = clubsList[0]


            println(currentClub)


            


            // Get the Name of the clubs


            clubName = currentClub["clubName"]?


            println(clubName)


     


     


    Ce qui donne :



    (
            {
            clubName = Mickey;
        },
            {
            clubName = Plutot;
        },
            {
            clubName = Donald;
        }
    )
    {
        clubName = Mickey;
    }
    Optional(Mickey)

    Mais impossible de transformer le currentClub["clubName"] "Optional(Mickey)" en String pour n'avoir que le texte.


  • Yes, j'ai quasiment trouvé !!!


     


            var clubsList = []


            var currentClub : AnyObject


            var clubName: AnyObject!


            


            // Get the clubs list


            let path: String? = NSBundle.mainBundle().pathForResource("Clubs", ofType: "plist")


            clubsList = NSArray(contentsOfFile: path!)


            println(clubsList)


            


            // Get the informations of the 1st club


            currentClub = clubsList[0]


            println(currentClub)


            


            // Get the Name of the clubs


            clubName = currentClub["clubName"]!


            println(clubName)



    (
            {
            clubName = Mickey;
        },
            {
            clubName = Plutot;
        },
            {
            clubName = Donald;
        }
    )
    {
        clubName = Mickey;
    }
    Mickey

    Par contre j'arrive pas à  faire le :



    cell.textLabel.text = clubName
  • Salut,


    J'ai fait un petit projet rapide (master detail) en reprenant ton code et tout fonctionne... Pas de plantage (OS 10.9.4, Xcode 6b6). As tu essayé un clean de on projet ? un reboot de la machine après install de Xcode ?


     


    Mais impossible de transformer le currentClub["clubName"] "Optional(Mickey)" en String pour n'avoir que le texte

     



     


    même avec un cast en String ?



    var clubStr: String = currentClub["clubName"] as String
    println(clubStr)

  • var clubName: String = currentClub["clubName"] as String

     "Swift dynamic cast failure"

  • Voici la solution que j'ai trouvée : (certainement pas la meilleure mais elle fonctionne)


     


           var clubName: AnyObject!


            


            // Get the informations of the 1st club


            currentClub = clubsList[indexPath!.row]


            


            // Get the Name of the clubs


            clubName = currentClub["clubName"]!  


     


            // String conversion


            let str = ("\(clubName!)")


            


            // Update textLabel of the cell


            cell.textLabel.text = str


     


    En espérèrent que mes déboires servent à  quelqu'un un jour.


    Merci aux personnes qui m'on données un coup de main.


  • LexxisLexxis Membre
    août 2014 modifié #22

    Vraiment étrange... je n'ai aucune erreur


     


    Tu aurais la possibilité de mettre en téléchargement ton projet pour voir ?


  • Paisible.frPaisible.fr Membre
    août 2014 modifié #23

    Code source qui fonctionne : http://www.paisible.fr/downloads/TestSwift.zip


     


    Si quelqu'un à  mieux à  proposer : je suis preneur.


  • Salut,


     


    Je vais télécharger ton projet en fin de journée également et voir pourquoi ça ne fonctionnait pas mais c'est très étrange en effet. 


    Normalement le code qu'on t'a donné devrait fonctionner. 


  • @magiic : en même temps la solution que je propose et qui fonctionne me semble plus proche de la philosophie Swift car elle ne passe pas par les types NSDictionnary, NSArray, etc... mais utilise plutôt les types Swift.


     


    Maintenant le coup de la transformation en String avec let str = ("\(clubName!)") ca me débecquete !!!

  • Oui. J'ai utilisé Array et Dictionary ça fonctionne. Ce qui me dérange et ce que je veux savoir c'est pourquoi le même code fonctionne chez moi et pas chez toi. Et oui, c'est sur que le coup de transformation en String n'est pas jolie et pratique.


  • Fait moi un zip de ton projet je l'essayerais chez moi.


  • Testé aussi (avec le code de ton premier post) et cela fonctionne...


  • J'ai profité d'une pause pour télécharger et regarder ton projet. J'ai modifié le code afin qu'il corresponde à  ce que j'aurais fais moi et tout fonctionne (pas trop changer par rapport à  ce que j'ai pu poster).


    Si le projet ci-joint ne marche pas chez toi c'est que ça vient d'une source extérieure au code. L'IDE ou autre.


     


     


  • @Magiic : j'ai essayé ton projet et il fonctionne parfaitement.


     


    J'ai probablement du commettre une erreur quelque part, mais je vois pas où !


     


    Merci quand même 


  • Je pense qu'il y a un réel problème avec mon projet en fait car si je prend ton code du  override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! et que je le met dans mon projet le var clubName : String? = currentClub["clubName"] as? String retourne toujours nil


     


    Pourtant le currentClub est correct : 



    {
        clubName = Mickey;
    }
    {
        clubName = Plutot;
    }
    {
        clubName = Donald;
    }
Connectez-vous ou Inscrivez-vous pour répondre.