159 votes

Qu'est-ce qu'une "valeur non enveloppée" en Swift ?

Je suis en train d'apprendre Swift pour iOS 8 / OSX 10.10 en suivant ce tutoriel et le terme " valeur non emballée " est utilisé à plusieurs reprises, comme dans ce paragraphe (sous Objets et classe ) :

Lorsque vous travaillez avec des valeurs facultatives, vous pouvez écrire ? avant les opérations comme les méthodes, les propriétés et les souscriptions. Si la valeur précédant le ? est nulle, tout ce qui suit le ? est ignoré et la valeur de l'ensemble de l'expression est nulle. Dans le cas contraire, la valeur optionnelle est déballée et tout ce qui suit le ? agit sur le valeur non emballée . Dans les deux cas, la valeur de l'expression entière est une valeur optionnelle.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

Je ne comprends pas, et j'ai cherché sur le web sans succès.

Qu'est-ce que cela signifie ?


Editar

D'après la réponse de Cezary, il y a une légère différence entre le résultat du code original et la solution finale (testée sur le terrain de jeu) :

Code original

Original code

La solution de Cezary

Cezary's solution

Les propriétés de la superclasse sont affichées dans la sortie dans le deuxième cas, alors qu'il y a un objet vide dans le premier cas.

Le résultat n'est-il pas censé être identique dans les deux cas ?

Questions et réponses connexes : Qu'est-ce qu'une valeur optionnelle en Swift ?

1 votes

La réponse de Cezary est parfaite. De plus, il existe un excellent livre d'introduction à Swift disponible pour GRATUIT sur iBooks

0 votes

@DanielStormApps Cet iBook est une version portable du tutoriel lié dans ma question :)

295voto

Cezary Wojcik Points 2886

Tout d'abord, vous devez comprendre ce qu'est un type optionnel. Un type optionnel signifie essentiellement que la variable peut être nil .

Ejemplo:

var canBeNil : Int? = 4
canBeNil = nil

Le point d'interrogation indique le fait que canBeNil peut être nil .

Cela ne fonctionnerait pas :

var cantBeNil : Int = 4
cantBeNil = nil // can't do this

Pour obtenir la valeur de votre variable si elle est facultative, vous devez le déballer . Cela signifie simplement mettre un point d'exclamation à la fin.

var canBeNil : Int? = 4
println(canBeNil!)

Votre code devrait ressembler à ceci :

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

Une parenthèse :

Vous pouvez également déclarer que les optionnels se déroulent automatiquement en utilisant un point d'exclamation au lieu d'un point d'interrogation.

Ejemplo:

var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

Donc une autre façon de corriger votre code est :

let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

EDIT :

La différence que vous voyez est exactement le symptôme du fait que la valeur optionnelle est enveloppé . Il y a une autre couche par-dessus. Le site non emballé montre juste l'objet droit parce qu'il est, eh bien, déballé.

Une comparaison rapide des terrains de jeux :

playground

Dans le premier et le deuxième cas, l'objet n'est pas automatiquement déballé, vous voyez donc deux "couches" ( {{...}} ), alors que dans le troisième cas, vous ne voyez qu'une seule couche ( {...} ) car l'objet est automatiquement déballé.

La différence entre le premier cas et les deux autres est que les deux derniers cas vous donneront une erreur d'exécution si optionalSquare est réglé sur nil . En utilisant la syntaxe du premier cas, vous pouvez faire quelque chose comme ceci :

if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}

1 votes

Merci pour cette explication claire ! Le code inclus dans ma question est tiré du tutoriel d'Apple (lien dans la question), et je suppose qu'il est censé fonctionner tel quel (et il le fait). Cependant, votre solution finale et la solution originale produisent des résultats différents (voir mon édition). Une idée ?

0 votes

Merci pour cette précision !

2 votes

Cool. Bonne explication. Mais je suis toujours confus. Pourquoi voudrais-je utiliser une valeur facultative ? Quand est-elle utile ? Pourquoi Apple a-t-elle créé ce comportement et cette syntaxe ?

17voto

CommaToast Points 1165

La réponse correcte existante est excellente, mais j'ai trouvé que pour comprendre pleinement, j'avais besoin d'une bonne analogie, car il s'agit d'un concept très abstrait et étrange.

Permettez-moi donc d'aider les autres développeurs "à cerveau droit" (pensée visuelle) en leur donnant une perspective différente en plus de la réponse correcte. Voici une bonne analogie qui m'a beaucoup aidé.

Analogie de l'emballage d'un cadeau d'anniversaire

Considérez les optionnels comme des cadeaux d'anniversaire emballés dans un papier rigide, dur et coloré.

On ne sait pas s'il y a quelque chose à l'intérieur de l'emballage avant de déballer le cadeau - il n'y a peut-être rien du tout à l'intérieur ! S'il y a quelque chose à l'intérieur, il pourrait s'agir d'un autre cadeau, lui aussi emballé, et qui, lui aussi, n'est pas emballé. peut ne rien contenir . Vous pourriez même déballer 100 cadeaux emboîtés pour finalement découvrir qu'il y avait rien que de l'emballage .

Si la valeur de l'option n'est pas nil vous avez maintenant révélé une boîte contenant quelque chose . Mais, surtout si la valeur n'est pas explicitement typée et qu'il s'agit d'une variable et non d'une constante prédéfinie, il se peut que vous deviez tout de même ouvrir la boîte avant que vous puissiez savoir quoi que ce soit de spécifique sur le contenu de la boîte. quel type ou ce qu'est la véritable valeur est.

Qu'est-ce qu'il y a dans la boîte ? ! Analogie

Même après avoir déballé la variable, vous êtes toujours comme Brad Pitt dans le dernière scène de SE7EN ( avertissement : spoilers et langage grossier et violence très Rated), car même après avoir déballé le cadeau, vous vous trouvez dans la situation suivante : vous avez maintenant nil ou une boîte contenant quelque chose (mais vous ne savez pas quoi).

Vous connaissez peut-être le type de quelque chose . Par exemple, si vous avez déclaré la variable comme étant de type , [Int:Any?] vous sauriez alors que vous avez un dictionnaire (potentiellement vide) avec des souscripteurs entiers qui produisent des contenus enveloppés de n'importe quel type.

C'est pourquoi l'utilisation des types de collections (dictionnaires et tableaux) en Swift peut être un peu compliquée.

Un exemple concret :

typealias presentType = [Int:Any?]

func wrap(i:Int, gift:Any?) -> presentType? {
    if(i != 0) {
        let box : presentType = [i:wrap(i-1,gift:gift)]
        return box
    }
    else {
        let box = [i:gift]
        return box
    }
}

func getGift() -> String? {
    return "foobar"
}

let f00 = wrap(10,gift:getGift())

//Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value.

var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0])

//Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is

let asdf : String = b4r!! as! String

print(asdf)

13voto

Billy A Points 56

Swift accorde une grande importance à la sécurité des types de véhicules. L'ensemble du langage Swift a été conçu dans un souci de sécurité. C'est l'une des caractéristiques de Swift et vous devriez l'accueillir à bras ouverts. Elle facilitera le développement d'un code propre et lisible et contribuera à éviter le plantage de votre application.

Toutes les options en Swift sont délimitées par le symbole ? symbole. En réglant le ? après le nom du type dans lequel vous déclarez que vous êtes optionnel, vous êtes essentiellement moulage ce pas comme le type dans lequel est avant le ? mais plutôt comme le en option type.


Note : Une variable ou un type Int es no la même chose que Int? . Ce sont deux types différents qui ne peuvent pas être opérés l'un sur l'autre.


Utilisation de l'option

var myString: String?

myString = "foobar"

Cela ne no signifie que vous travaillez avec un type de String . Cela signifie que vous travaillez avec un type de String? (Chaîne facultative, ou Chaîne facultative). En fait, chaque fois que vous essayez de

print(myString)

au moment de l'exécution, la console de débogage affichera Optional("foobar") . Le " Optional() La partie " " indique que cette variable peut avoir ou non une valeur au moment de l'exécution, mais qu'il se trouve qu'elle contient actuellement la chaîne "foobar". Ce " Optional() L'indication " " demeurera à moins que vous ne fassiez ce que l'on appelle "déballer" la valeur optionnelle.

Déballage un optionnel signifie que vous coulez maintenant ce type comme non-optionnel. Cela va générer un nouveau type et affecter la valeur qui résidait dans cette option au nouveau type non-optionnel. De cette façon, vous pouvez effectuer des opérations sur cette variable, car le compilateur a garanti qu'elle aurait une valeur solide.


Le déballage conditionnel vérifiera si la valeur de l'option est nil ou non. Si ce n'est pas le cas nil il y aura une variable constante nouvellement créée à laquelle sera attribuée la valeur et non emballé dans la constante non optionnelle. Et à partir de là, vous pouvez utiliser en toute sécurité le non-optionnel dans la constante if bloc.

Remarque : vous pouvez donner à votre constante à déballage conditionnel le même nom que la variable facultative que vous déballer.

if let myString = myString {
    print(myString)
    // will print "foobar"
}

Le déballage conditionnel des optionnels est le moyen le plus propre d'accéder à la valeur d'un optionnel, car s'il contient une valeur nulle, tout ce qui se trouve dans le bloc if let ne sera pas exécuté. Bien sûr, comme toute instruction if, vous pouvez inclure un bloc else

if let myString = myString {
    print(myString)
    // will print "foobar"
}
else {
    print("No value")
}

Déballage forcé se fait en employant ce que l'on appelle le ! ("bang"). Cette méthode est moins sûre mais permet tout de même à votre code de compiler. Cependant, chaque fois que vous utilisez l'opérateur bang, vous devez être certain à 1000% que votre variable contient bien une valeur solide avant de la déballer de force.

var myString: String?

myString = "foobar"

print(myString!)

Ce qui précède est un code Swift tout à fait valable. Il imprime la valeur de myString qui a été défini comme "foobar". L'utilisateur verrait foobar imprimé dans la console et c'est à peu près tout. Mais supposons que la valeur n'a jamais été définie :

var myString: String?

print(myString!) 

Nous avons maintenant une situation différente sur les bras. Contrairement à l'Objective-C, chaque fois que l'on tente de déballer de force une option, et que l'option n'a pas été définie et est nil si vous essayez de déballer l'option pour voir ce qu'il y a à l'intérieur, votre application se plantera.


Déballage avec moulage de type . Comme nous l'avons dit précédemment, pendant que vous êtes unwrapping l'optionnel que vous projetez en fait vers un type non optionnel, vous pouvez également projeter le non-optionnel vers un type différent. Par exemple :

var something: Any?

Quelque part dans notre code, la variable something sera défini avec une certaine valeur. Peut-être que nous utilisons des génériques ou peut-être qu'il y a une autre logique qui se passe et qui provoque ce changement. Donc, plus tard dans notre code, nous voulons utiliser something tout en étant capable de le traiter différemment s'il s'agit d'un autre type. Dans ce cas, vous voudrez utiliser l'option as mot-clé pour le déterminer :

Note : Le as L'opérateur est la façon dont vous tapez cast en Swift.

// Conditionally
if let thing = something as? Int {
    print(thing) // 0
}

// Optionally
let thing = something as? Int
print(thing) // Optional(0)

// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised

Remarquez la différence entre les deux as mots-clés. Comme précédemment, lorsque nous avons déballé de force une option, nous avons utilisé le mot-clé ! opérateur de bang pour le faire. Ici, vous ferez la même chose, mais au lieu de le présenter comme un simple non-optionnel, vous le présenterez également comme un Int . Et il doit être capable d'être abattu comme Int sinon, comme utiliser l'opérateur bang lorsque la valeur est nil votre application se plantera.

Et pour pouvoir utiliser ces variables dans une opération mathématique quelconque, elles doivent être déballées.

Par exemple, dans Swift, seuls les types de données numériques valides du même type peuvent être exploités les uns sur les autres. Lorsque vous convertissez un type avec l'attribut as! vous forcez la baisse de cette variable comme si vous étiez certains il est de ce type, donc sûr d'opérer et de ne pas planter votre application. Cela ne pose pas de problème tant que la variable est effectivement du même type que celui auquel elle est affectée, sinon vous vous retrouverez avec un problème sur les bras.

Néanmoins, le casting avec as! permettra à votre code de compiler. En coulant avec un as? c'est une autre histoire. En effet, as? déclare que votre Int comme un type de données complètement différent.

Maintenant, c'est Optional(0)

Et si vous avez déjà essayé de faire vos devoirs en écrivant quelque chose comme

1 + Optional(1) = 2

Votre professeur de mathématiques vous aurait probablement donné un "F". Pareil pour Swift. Sauf que Swift préfère ne pas compiler du tout plutôt que de vous donner une note. Parce qu'à la fin de la journée, l'option peut en fait être nulle. .

Safety First Kids.

0voto

gkgy Points 39

'?' signifie expression de chaînage optionnelle

le "!moyen" est force-valeur
enter image description here

0voto

sumit rathore Points 83

Il existe 7 façons de déballer une valeur optionnelle en Swift.

  1. Reliure facultative - sûre
  2. Option de chaînage - Sécurité
  3. Motif optionnel - Sécurité
  4. Néant Coalescence - Sécurité
  5. Guard Statement - Safe
  6. Le déballage de force - dangereux
  7. Le déballage implicite - non sécurisé

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X