web-dev-qa-db-fra.com

Qu'est-ce qu'une "valeur non emballée" dans Swift?

J'apprends Swift pour iOS 8/OSX 10.10 en suivant ce tutoriel , et le terme " valeur non enveloppée "est utilisé plusieurs fois, comme dans ce paragraphe (sous Objets et classe ):

Lorsque vous travaillez avec des valeurs optionnelles, vous pouvez écrire? avant les opérations telles que méthodes, propriétés et indice. Si la valeur avant le? est nul, tout après le? est ignoré et la valeur de l'expression entière est nil. Sinon, la valeur facultative est décompressée , et tout ce qui suit le? agit sur la valeur non enveloppée . Dans les deux cas, la valeur de l'expression entière est une valeur facultative.

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

Je ne comprends pas, et cherché sur le web sans chance.

Que cela veut-il dire?


Modifier

D'après la réponse de Cezary, il existe une légère différence entre la sortie du code d'origine et la solution finale (testée sur un terrain de jeu):

Code d'origine

Original code

La solution de Cezary

Cezary's solution

Les propriétés de la superclasse sont montré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/Réponses connexes: Qu'est-ce qu'une valeur optionnelle dans Swift?

154
Bigood

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

Exemple:

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érouler . 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

Un sidenote:

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

Exemple:

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

Une autre façon de corriger votre code est donc:

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

MODIFIER:

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. La version non emballée montre simplement l'objet droit car il est, non, enveloppé.

Une comparaison rapide du terrain de jeu:

playground

Dans le premier et le deuxième cas, l’objet n’est pas automatiquement déballé. Vous voyez donc deux "calques" ({{...}}), alors que dans le troisième cas, vous ne voyez qu’un seul calque ({...}) car l'objet est automatiquement déballé.

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

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

La bonne réponse existante est excellente, mais j’ai trouvé que pour que je puisse comprendre tout cela, il me fallait une bonne analogie, car c’était un concept très abstrait et très étrange.

Alors, laissez-moi aider les autres développeurs "pensifs" (en 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 d'emballage de cadeau d'anniversaire

Considérez les optionnels comme des cadeaux d’anniversaire présentés dans un emballage rigide, dur et coloré.

Vous ne savez pas s’il ya quelque chose à l’intérieur de l’emballage jusqu’à ce que vous dérouliez le cadeau - peut-être qu’il n’ya rien du tout à l’intérieur! S'il y a quelque chose à l'intérieur, cela pourrait être encore un autre cadeau, qui est également emballé, et qui aussi pourrait ne rien contenir . Vous pourriez même déballer 100 cadeaux imbriqués pour finalement découvrir qu'il n'y avait que des enveloppements .

Si la valeur de facultatif n'est pas nil, vous venez de révéler une boîte contenant quelque chose . Mais surtout si la valeur n’est pas explicitement typée et qu’elle est une variable et non une constante prédéfinie, vous devrez peut-être toujours ouvrir la boîte avant de savoir quoi que ce soit de particulier. la boîte, comme de quel type il s’agit, ou quelle est la valeur réelle .

Que contient la boîte?! Analogie

Même après avoir déroulé la variable, vous restez comme Brad Pitt dans le dernière scène de SE7EN ( warning : spoilers et un langage grossier très R-rated et violence), car même après avoir déballé le présent, 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 déclariez la variable comme étant de type, [Int:Any?], vous sauriez que vous avez un dictionnaire (potentiellement vide) avec des indices entiers qui renvoient des contenus encapsulés de tous les types précédents.

C’est pourquoi traiter avec les types de collections (Dictionnaires et Tableaux) dans Swift peut devenir assez poilu.

Exemple:

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)
17
CommaToast

Swift accorde une grande importance à la sécurité des types. Tout le langage Swift a été conçu dans un souci de sécurité. C’est l’une des caractéristiques de Swift et vous devriez la recevoir à bras ouverts. Cela vous aidera à développer du code propre et lisible et à éviter que votre application ne plante.

Toutes les options dans Swift sont marquées du symbole ?. En définissant ? après le nom du type dans lequel vous déclarez que vous êtes facultatif, vous transformez ceci non comme le type dans lequel est avant le ?, mais à la place du type facultatif .


Remarque: Une variable ou un type Int est pas identique à Int?. Ils sont deux types différents qui ne peuvent pas être exploités l'un sur l'autre.


tilisation facultative

var myString: String?

myString = "foobar"

Ceci not signifie que vous travaillez avec un type de String. Cela signifie que vous utilisez 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 imprimera Optional("foobar"). La partie "Optional()" indique que cette variable peut avoir ou non une valeur au moment de l'exécution, mais elle contient la chaîne "foobar". Cette indication "Optional()" restera active sauf si vous effectuez ce que l'on appelle "décompresser" la valeur facultative.

nwrapping un optionnel signifie que vous convertissez maintenant ce type en non optionnel. Cela générera un nouveau type et affectera la valeur résidant dans ce type facultatif au nouveau type non facultatif. De cette façon, vous pouvez effectuer des opérations sur cette variable, car le compilateur a garanti qu’il avait une valeur solide.


Déconditionnement conditionnel vérifiera si la valeur de l'option est nil ou non. Si ce n'est pas nil, il y aura une nouvelle variable constante qui se verra attribuer la valeur et non enveloppée dans la constante non facultative. . Et à partir de là, vous pouvez utiliser en toute sécurité le non facultatif du bloc if.

Remarque: Vous pouvez attribuer le même nom à votre constante conditionnellement non enveloppée que la variable facultative que vous extrayez.

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

Le désemballage conditionnel des options est le moyen le plus propre d’accéder à une valeur d’option, car si elle contient une valeur nulle, tout le contenu du bloc if let ne s’exécutera pas. 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é est effectué en utilisant ce que l’on appelle l’opérateur ! ("bang"). Ceci est moins sûr mais permet toujours à votre code de compiler. Cependant, chaque fois que vous utilisez l'opérateur bang, vous devez être sûr à 1000% que votre variable contient en fait une valeur solide avant le décompression forcée.

var myString: String?

myString = "foobar"

print(myString!)

Ce qui précède est entièrement valide Swift code. Il affiche la valeur de myString définie 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!) 

Maintenant, nous avons une situation différente sur nos mains. Contrairement à Objective-C, chaque fois que vous tentez de dérouler de force un facultatif et que celui-ci n'a pas été défini et qu'il est nil, vous essayez de le dérouler pour voir ce qui se bloque dans votre application.


Déballage avec moulage de type. Comme nous l'avons dit précédemment, même si vous êtes unwrapping le type facultatif que vous convertissez en un type non facultatif, vous pouvez également convertir le type non facultatif en un type différent. Par exemple:

var something: Any?

Quelque part dans notre code, la variable something sera définie avec une valeur. Peut-être utilisons-nous des médicaments génériques ou peut-être existe-t-il une autre logique qui entraînera un changement. Donc plus tard dans notre code, nous voulons utiliser something mais pouvoir le traiter différemment s'il s'agit d'un type différent. Dans ce cas, vous souhaiterez utiliser le mot clé as pour déterminer ceci:

Remarque: L'opérateur as vous permet de taper cast dans 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

Notez la différence entre les deux mots-clés as. Comme précédemment, lorsque nous avons forcé un optionnel, nous avons utilisé l'opérateur ! bang pour le faire. Ici, vous ferez la même chose, mais au lieu de lancer comme un non-optionnel, vous le diffuserez aussi comme Int. Et il doit pouvoir être downcast comme Int, sinon, comme si vous utilisiez l'opérateur bang lorsque la valeur est nil votre l'application va planter.

Et pour utiliser ces variables dans une sorte ou une opération mathématique, elles doivent être décomposées pour pouvoir le faire.

Par exemple, dans Swift, seuls les types de données numériques valables du même type peuvent être utilisés les uns sur les autres. Lorsque vous transformez un type avec le as!, vous forcez le downcast de cette variable comme si vous étiez certain il est de ce type, donc sûr à utiliser et ne bloque pas votre application. C’est acceptable tant que la variable est effectivement du type que vous voulez lui attribuer, sinon vous aurez un désordre sur les mains.

Néanmoins, le casting avec as! permettra à votre code de se compiler. Le casting avec un as? est une histoire différente. En fait, as? déclare 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". Même avec Swift. Sauf que Swift préfère ne pas compiler du tout plutôt que de vous attribuer une note. En fin de compte, l’option est peut-être nulle.

La sécurité d'abord, les enfants.

13
Brandon A

'?' signifie une expression de chaîne optionnelle

le '!' signifie est force-valeur
enter image description here

0
gkgy