Dictionary VS NSDictionary

NiClouNiClou Membre
août 2014 modifié dans Objective-C, Swift, C, C++ #1

Hello,


Comme beaucoup je m'essaie au Swift et je rencontre quelques problèmes.

J'ai la méthode d'exemple suivante:



-(void)handleInformations:(NSDictionary*)infos{
if (!infos)
return ;

if ([infos objectForKey:@p])
[self goToScreen:[infos objectForKey:@p]];
}

Lorsque j'essaie de la ré ecrire en swift, je suis confronté a des problèmes swift.

Problème que je ne rencontre pas si j'utilise un NSDictionary.



func handleInformations(infos: Dictionary<String, Int>) {
if (infos.isEmpty) {
return
}

if (infos["p"] != nil) {
self.goToScreen(infos["p"] as Int) //La j'ai un problème
}
}

L'erreur est la suivante: 



 


Could not find an overload for 'subscript' that accepts the supplied arguments



 


Des idées?


 



EDIT: CocoaCafe est un bon RubberDuck: La méthode goToScreen attendait un String et j'ai oublié le "!" après le "as Int"...


J'ai vraiment du mal avec ces "?/!"


Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur



    func handleInformations(infos: Dictionary<String, Int>) {
    if (infos.isEmpty) {
    return
    }

    if (infos["p"] != nil) {
    self.goToScreen(infos["p"] as Int) //La j'ai un problème
    }
    }



     


    Avec le Dictionary, ce n'est pas nécessaire d'utiliser infos["p"] asInt, car c'est un Dictionary<String, Int>, du coup la valeur renvoyé sera toujours un Int.

  • AliGatorAliGator Membre, Modérateur
    août 2014 modifié #3

    Avec le Dictionary, ce n'est pas nécessaire d'utiliser infos["p"] asInt, car c'est un Dictionary<String, Int>, du coup la valeur renvoyé sera toujours un Int.



    Plus exactement la valeur renvoyée par infos["p"] ne sera pas un "Int" mais sera un "Int?" (c'est à  dire un Optional<Int>) puisque tu peux ne pas avoir de valeur dans le dictionnaire pour la clé demandée, donc il peut tout à  fait retourner nil (= "Optional.None", soit une absence de valeur).


    Et du coup il faut en effet :


    • Soit forcer le unwrapping, en faisant un "as Int!" " ce qui n'est acceptable que si jamais tu as bien vérifié avant que infos["p"] avait une valeur, ce que tu as fais dans ton code donc ça va (même si tu l'as fait à  la façon Objective-C) ; car sinon, si tu n'as pas la vérification et que c'est nil mais que tu forces à  unwrapper quand même, c'est le plantage assuré ;)
    • Soit, solution préconisée et à  préférer car c'est "the Swift way", faire cette vérification comme quoi infos["p"] est non-nil... avec la syntaxe du "if let" (ce qu'on appelle officiellement le "Optional Binding"), ce qui est à  la fois plus sexy, plus "Swift", et évite d'avoir à  faire un cast.

    if let screenNum = infos["p"] {
    self.goToScreen(screenNum)
    }

    La syntaxe "if let xx = optionalExpr" teste si l'expression optionalExpr (qui est une expression retournant un optional) retourne une valeur.


    • Si oui, va la "binder" (l'affecter) à  la constante déclarée par le "let xx = ". Du coup, dans le corps du "if", tu peux directement utiliser cette variable "xx" (screenNum dans mon exemple) qui aura forcément une valeur et ne sera plus un Optional (sera donc un Int et non plus un Int?, puisque vu que ça a passé le "if" donc c'est forcément non-nil).
    • Si par contre l'expression optionalExpr est nil (= n'a pas de valeur = est égale à  la valeur d'énum Optional.None) alors tu ne rentres même pas dans le if et il n'y a même pas d'affectation à  une quelconque constante "xx".

    Cette syntaxe de l'Optional Binding ("if let ...") est beaucoup + dans l'esprit de Swift que la méthode "à  la Objective-C" de faire "if (infos["p"] != nil) { /* code qui utilise infos["p"] */ }". Elle a en plus l'avantage de ne faire le "lookup" / calcul de l'expression qu'une seule fois (il ne cherche la valeur de la clé "p" dans le dictionnaire "infos" qu'une seule fois, et s'il la trouve il l'affecte à  screenNum " contrairement à  si tu utilisais infos["p"] à  la fois dans la condition et dans le corps du "if" à  la mode Objective-C où il aurait à  évaluer l'expression / rechercher la valeur dans le dico 2 fois)


    En fait en pratique, c'est très rare d'avoir à  mettre un "!" derrière une variable ou d'avoir à  forcer un cast en un "Type!". Il faut toujours préférer soit l'Optional Binding, soit l'Optional Chaining (utilisation du "?" après la variable), selon les cas / le besoin.


     


    Faire du forced-unwrapping avec "!" c'est risquer le crash au Runtime si la variable est nil et qu'on force à  l'unwrapper quand même " plantage assuré par définition. Alors que l'Optional Binding permet de s'assurer qu'on n'unwrap pas un Optional (qu'on n'essaye pas d'accéder à  sa valeur interne) dans le cas où ce dernier est nil (n'a en fait pas de valeur interne, donc).


  • Joanna CarterJoanna Carter Membre, Modérateur

    Merci pour ces précisions plus précis.


     


    J'ai évité la complexité en évitant d'être trop complexe.  :P  B)


  • Whouaou.


    Ya beaucoup de choses qui s'expliquent en effet.


    C'est vrai qu'on a très peu d'informations concernant les bonnes méthodes à  utiliser.


     


    Merci a vous deux pour ces réponses, on ne peut plus precise.


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