Swift, plist, Dictionnary et UITableView
Paisible.fr
Membre
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.
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
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 :
Visiblement ca plante sur le cell.textLabel.text = currentClub.valueForKey("clubName") as String
Si valueForKey renvoie nil, ça peut planter
@joanna : le println(currentClub) affiche bien une valeur pour la clé "clubName"
Hum on progresse, un println(currentClub.valueForKey("clubName")) renvoi :
Et
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.
Ou ça ?
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 !
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.
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 :
OK ca évite le crash mais j'ai jamais ma valeur !
Donc ça m'avance pas beaucoup
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.
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 :
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 :
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 :
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)
Par contre j'arrive pas à faire le :
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 ?
même avec un cast en 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.
Vraiment étrange... je n'ai aucune erreur
Tu aurais la possibilité de mettre en téléchargement ton projet pour voir ?
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 :