Le Swift Guide du langage de programmation présente l'exemple suivant:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
var tenant: Person?
deinit { println("Apartment #\(number) is being deinitialized") }
}
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
//From Apple's “The Swift Programming Language” guide (https://developer.Apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)
Puis, lors de l'attribution de l'appartement à la personne, ils utilisent un point d'exclamation pour "décompresser l'instance":
john!.apartment = number73
Que signifie "décompresser l'instance"? Pourquoi est-ce nécessaire? En quoi est-ce différent de simplement faire ce qui suit:
john.apartment = number73
Je suis très nouveau dans la langue Swift. J'essaie juste de comprendre les bases.
UPDATE:
Le gros morceau du puzzle qui me manquait (et non pas indiqué directement dans les réponses - du moins pas au moment d'écrire ceci) est que lorsque vous procédez comme suit:
var john: Person?
cela ne signifie PAS que "john
est de type Person
et il pourrait être nul", comme je le pensais à l'origine. Je ne comprenais tout simplement pas que Person
et Person?
sont des types complètement séparés. Une fois, j’ai compris que toutes les autres ?
, !
et les bonnes réponses ci-dessous avaient beaucoup plus de sens.
Que signifie "décompresser l'instance"? Pourquoi est-ce nécessaire?
Autant que je peux m'entraîner (c'est très nouveau pour moi aussi) ...
Le terme "enveloppé" implique que nous devrions penser à une variable optionnelle comme un cadeau, enveloppée dans du papier brillant, qui pourrait (malheureusement!) Être vide .
Lorsqu'elle est "encapsulée", la valeur d'une variable optionnelle est une énumération avec deux valeurs possibles (un peu comme un booléen). Cette énumération indique si la variable contient une valeur (Some(T)
) ou non (None
).
S'il existe une valeur, vous pouvez l'obtenir en "dépliant" la variable (en obtenant la T
de Some(T)
).
En quoi
john!.apartment = number73
est-il différent dejohn.apartment = number73
? (Paraphrasé)
Si vous écrivez le nom d'une variable optionnelle (par exemple text john
, sans le !
), cela fait référence à l'énumération "wrapped" (Some/None), pas à la valeur elle-même (T). Donc, john
n'est pas une instance de Person
, et n'a pas de membre apartment
:
john.apartment
// 'Person?' does not have a member named 'apartment'
La valeur réelle de Person
peut être décomposée de différentes manières:
john!
(donne la valeur Person
si elle existe, erreur d'exécution si elle est nulle)if let p = john { println(p) }
(exécute la println
si la valeur existe)john?.learnAboutSwift()
(exécute cette méthode inventée si la valeur existe)J'imagine que vous choisissez l'une de ces méthodes pour décompresser, en fonction de ce qui devrait se passer dans le cas zéro et de sa probabilité. Cette conception de langage oblige le cas nul à être traité explicitement, ce qui, je suppose, améliore la sécurité par rapport à Obj-C (où il est facile d’oublier de traiter le cas nul).
Mise à jour :
Le point d'exclamation est également utilisé dans la syntaxe pour déclarer "Optionsals implicitement non enveloppées".
Dans les exemples précédents, la variable john
a été déclarée comme var john:Person?
et il s’agit d’un Facultatif. Si vous voulez connaître la valeur réelle de cette variable, vous devez la décompresser en utilisant l’une des trois méthodes ci-dessus.
Si elle était plutôt déclarée comme var john:Person!
, la variable serait une option implicitement non enveloppée (voir la section contenant cet en-tête dans le manuel d'Apple). Il n'est pas nécessaire de décompresser ce type de variable lors de l'accès à la valeur, et john
peut être utilisé sans syntaxe supplémentaire. Mais le livre d'Apple dit:
Les options non implicites non enveloppées ne doivent pas être utilisées lorsqu'il est possible qu'une variable devienne nulle par la suite. Utilisez toujours un type facultatif normal si vous devez rechercher une valeur nulle pendant la durée de vie d'une variable.
Mise à jour 2 :
L'article " Intéressant Swift Caractéristiques " de Mike Ash donne une certaine motivation pour les types optionnels. Je pense que c'est bien, une écriture claire.
Mise à jour 3 :
Un autre article utile sur l'utilisation de implicitement implicite pour le point d'exclamation: " Swift and the Last Mile " de Chris Adamson. L'article explique qu'il s'agit d'une mesure pragmatique de Apple utilisée pour déclarer les types utilisés par leurs frameworks Objective-C susceptibles de contenir nil. Déclarer un type comme étant facultatif (avec ?
) ou implicitement non encapsulé (avec !
) est un "compromis entre sécurité et commodité". Dans les exemples donnés dans l'article, Apple ont choisi de déclarer les types implicitement non enveloppés, ce qui rend le code d'appel plus pratique, mais moins sûr.
Peut-être Apple pourrait-il explorer leurs cadres à l'avenir, en supprimant l'incertitude des paramètres implicitement non enveloppés ("probablement jamais nul") et en les remplaçant par des éléments optionnels ("pourrait certainement être nul en particulier [espérons-le, documenté!] circonstances ") ou des déclarations standard non facultatives (" n'est jamais jamais "), basées sur le comportement exact de leur code Objective-C.
Voici ce que je pense est la différence:
var john: Person?
Signifie que john peut être nul
john?.apartment = number73
Le compilateur interprétera cette ligne comme suit:
if john != nil {
john.apartment = number73
}
Tandis que
john!.apartment = number73
Le compilateur interprétera cette ligne simplement:
john.apartment = number73
Par conséquent, en utilisant! va déballer l'instruction if et la faire courir plus vite, mais si john est nil, une erreur d'exécution se produira.
Donc, encapsuler ici ne signifie pas que la mémoire est encapsulée, mais que le code est encapsulé, dans ce cas, il est encapsulé avec une instruction if, et parce que Apple est très attentif aux performances d'exécution, ils veulent pour vous permettre de faire fonctionner votre application avec les meilleures performances possibles.
Mise à jour:
Revenons à cette réponse au bout de 4 ans, alors que Stackoverflow en tirait la plus haute réputation. J'ai un peu mal compris le sens de la décompression à l'époque. Maintenant, après 4 ans, je pense que le sens de la décompression est d’élargir le code à partir de sa forme compacte originale. Cela signifie également que vous devez éliminer le flou autour de cet objet, car nous ne sommes pas sûrs que, par définition, il est nul ou non. Tout comme la réponse d'Ashley ci-dessus, considérez cela comme un cadeau qui ne pourrait rien contenir. Mais je pense toujours que le déchiffrement est un déchiffrement de code et non un décompressage basé sur la mémoire comme enum.
TL; DR
Que signifie un point d'exclamation dans le langage Swift?
Le point d'exclamation indique en effet: "Je sais que cette option a définitivement une valeur; veuillez l’utiliser. "C’est ce que l’on appelle le déroulement forcé de la valeur de l’option:
Exemple
let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."
let assumedString: String! = "An implicitly unwrapped optional string."
print(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."
Si john était une variable optionnelle (déclarée ainsi)
var john: Person?
alors il serait possible pour john de n'avoir aucune valeur (dans le jargon ObjC, valeur nulle)
Le point d'exclamation dit au compilateur: "Je sais que cela a une valeur, vous n'avez pas besoin de le tester". Si vous ne voulez pas l'utiliser, vous pouvez le tester conditionnellement:
if let otherPerson = john {
otherPerson.apartment = number73
}
L'intérieur de ceci n'évaluera que si john a une valeur.
Quelques grandes perspectives à ajouter aux autres réponses utiles mais plus détaillées:
Dans Swift, le point d'exclamation apparaît dans plusieurs contextes:
let name = nameLabel!.text
var logo: UIImageView!
logo.image = thing as! UIImage
try! NSJSONSerialization.JSONObjectWithData(data, [])
Chacun de ceux-ci est une construction de langage différente avec un sens différent, mais ils ont tous trois points communs importants:
Lorsque vous utilisez !
dans Swift, vous dites essentiellement: "Hé, compilateur, je sais que vous pensez qu'une erreur pourrait se produire ici, mais je connais avec la certitude absolue que cela ne le sera jamais. "
Tout le code valide n’entre pas dans la boîte du système de types au moment de la compilation de Swift - ou la vérification de type statique du langage , en fait. Il existe des situations où vous pouvez prouver logiquement qu’une erreur ne se produira jamais, mais vous ne pouvez pas le prouver au compilateur . C’est pourquoi les concepteurs de Swift ont ajouté ces fonctionnalités en premier lieu.
Cependant, chaque fois que vous utilisez !
, vous n’excluez pas de chemin de récupération pour une erreur, ce qui signifie que…
Un point d'exclamation dit également: "Hey Swift, je suis donc certain que cette erreur ne peut jamais arriver, il est préférable que vous ( plantiez mon application entière . que ce soit pour moi de coder un chemin de récupération pour cela. "
C’est une affirmation dangereuse. Cela peut être le bon: dans un code critique où vous avez beaucoup réfléchi aux invariants de votre code, il se peut que la sortie fictive soit pire qu’un crash.
Cependant, quand je vois !
dans la nature, il est rarement utilisé aussi consciencieusement. Au lieu de cela, cela signifie trop souvent que "cette valeur était facultative et je ne pensais pas vraiment trop pourquoi cela pouvait être nul ou comment gérer correctement cette situation, mais en ajoutant !
l'a fait compiler… donc mon code est correct, n'est-ce pas?
Attention à l'arrogance du point d'exclamation. Au lieu…
Chacune de ces constructions !
a un équivalent ?
qui vous oblige à traiter le cas d'erreur/nil:
if let name = nameLabel?.text { ... }
var logo: UIImageView?
logo.image = thing as? UIImage
try? NSJSONSerialization.JSONObjectWithData(data, [])
Si vous êtes tenté d'utiliser !
, il est toujours bon de bien examiner pourquoi vous n'utilisez pas ?
. Faire planter votre programme est-il vraiment la meilleure option si l'opération !
échoue? Pourquoi cette valeur est-elle facultative/accessible?
Existe-t-il un chemin de récupération raisonnable que votre code pourrait emprunter en cas d'erreur/d'erreur? Si oui, codez-le.
Si elle ne peut pas être nulle, si l’erreur ne peut jamais se produire, existe-t-il un moyen raisonnable de retravailler votre logique pour que le compilateur le sache? Si oui, fais-le; votre code sera moins sujet aux erreurs.
Il y a des moments où il n'y a pas de moyen raisonnable de gérer une erreur, et le fait de simplement ignorer l'erreur - et donc de traiter des données erronées - serait pire que de planter. Ceux sont les moments où il faut utiliser le déballage forcé.
Je recherche périodiquement toute la base de code de !
et en vérifie chaque utilisation. Très peu d'usages résistent à l'examen. (Au moment d'écrire ces lignes, tout le framework Siesta en possède exactement deuxinstances .)
Cela ne veut pas dire que vous ne devriez jamais utiliser !
dans votre code - vous devez simplement l’utiliser avec attention , et ne jamais en faire la option par défaut.
john
est une option var
. Donc, peut contenir une valeur nil
. Pour vous assurer que la valeur n'est pas nulle, utilisez un !
à la fin du nom var
.
De la documentation
“Une fois que vous êtes certain que l’optif contient bien une valeur, vous pouvez accéder à sa valeur sous-jacente en ajoutant un point d’exclamation (!) À la fin du nom de l’optif. Le point d’exclamation indique en fait:“ Je sais que cette option a définitivement une valeur, merci de l’utiliser. ”
Une autre façon de vérifier la valeur non nulle est
if let j = json {
// do something with j
}
Voici quelques exemples:
var name:String = "Hello World"
var Word:String?
Où Word
est une valeur facultative. signifie qu'il peut contenir ou non une valeur.
Word = name
Ici name
a une valeur pour pouvoir l’affecter
var cow:String = nil
var dog:String!
Où dog
est déplié de force signifie qu'il doit contenir une valeur
dog = cow
L'application va planter parce que nous assignons nil
à non emballé
Dans ce cas...
var John: Personne!
cela signifie que, initialement, John aura une valeur nulle, il sera défini et une fois défini, il ne sera plus jamais réinitialisé. Par conséquent, pour plus de commodité, je peux utiliser la syntaxe la plus simple pour accéder à une variable facultative, car il s'agit d'une "option facultative implicitement non enveloppée".
Si vous venez d'un langage de la famille C, vous penserez "pointeur sur un objet de type X qui pourrait être l'adresse mémoire 0 (NULL)", et si vous venez d'un langage à typage dynamique, vous serez pensant "Objet qui est probablement de type X mais peut être de type non défini". Aucune de ces réponses n'est en réalité correcte, bien que le premier soit proche.
Vous devriez penser à cela comme si c'était un objet comme:
struct Optional<T> {
var isNil:Boolean
var realObject:T
}
Lorsque vous testez votre valeur facultative avec foo == nil
, elle renvoie réellement foo.isNil
et lorsque vous dites foo!
, elle renvoie foo.realObject
avec une assertion qui foo.isNil == false
. Il est important de noter cela car, si foo
est réellement nul lorsque vous faites foo!
, il s'agit d'une erreur d'exécution. Vous voudrez donc généralement utiliser un let conditionnel, à moins que vous ne soyez vraiment sûr que la valeur ne pas être nul. Ce genre de ruse signifie que le langage peut être fortement typé sans vous obliger à tester si les valeurs sont nulles partout.
En pratique, cela ne se comporte pas vraiment comme ça parce que le travail est fait par le compilateur. A un niveau élevé, il existe un type Foo?
séparé de Foo
et empêchant les fonctions acceptant le type Foo
de recevoir une valeur nulle, mais à un niveau bas une valeur optionnelle isn pas un objet vrai car il n’a pas de propriétés ou de méthodes; il est probable qu’il s’agisse d’un pointeur pouvant avoir la valeur NULL (0) avec le test approprié lors du retrait forcé.
Il existe une autre situation dans laquelle vous verriez qu'un point d'exclamation se trouve sur un type, comme dans:
func foo(bar: String!) {
print(bar)
}
C’est à peu près équivalent à accepter une option avec un déroulement forcé, c’est-à-dire:
func foo(bar: String?) {
print(bar!)
}
Vous pouvez utiliser ceci pour avoir une méthode qui accepte techniquement une valeur optionnelle, mais aura une erreur d’exécution si elle est nulle. Dans la version actuelle de Swift, cela contourne apparemment l'assertion is-not-nil, vous aurez donc une erreur de bas niveau. Généralement, ce n'est pas une bonne idée, mais cela peut être utile lors de la conversion de code depuis une autre langue.
Si vous êtes familier avec C #, cela ressemble aux types Nullable qui sont également déclarés à l'aide d'un point d'interrogation:
Person? thisPerson;
Et le point d'exclamation dans ce cas équivaut à accéder à la propriété .Value du type nullable comme ceci:
thisPerson.Value
Le ! signifie que vous forcez à dérouler l'objet le! suit. Vous trouverez plus d'informations dans la documentation d'Apple, à l'adresse suivante: https://developer.Apple.com/library/ios/documentation/Swift/conceptual/Swift_Programming_Language/TheBasics.html
Dans l’objectif C, les variables sans valeur étaient égales à "nil" (il était également possible d’utiliser des valeurs "nil" identiques à 0 et à false), il était donc possible d’utiliser des variables dans des instructions conditionnelles (les variables ayant les mêmes valeurs que "TRUE"). 'et ceux sans valeur étaient égaux à' FALSE ').
Swift assure la sécurité du type en fournissant une "valeur optionnelle". Cela évite les erreurs d’attribution de variables de types différents.
Ainsi, dans Swift, seuls des booléens peuvent être fournis sur des instructions conditionnelles.
var hw = "Hello World"
Ici, même si 'hw' est une chaîne, elle ne peut pas être utilisée dans une instruction if comme dans Objective C.
//This is an error
if hw
{..}
Pour cela, il doit être créé comme,
var nhw : String? = "Hello World"
//This is correct
if nhw
{..}
En bref (!): Une fois que vous avez déclaré une variable et que vous êtes certain que celle-ci contient une valeur.
let assumedString: String! = "Some message..."
let implicitString: String = assumedString
sinon, vous devriez le faire chaque fois que vous passez une valeur ...
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
Le ! à la fin d'un objet indique que l'objet est facultatif et à se dérouler s'il peut sinon renvoyer une valeur nulle. Ceci est souvent utilisé pour intercepter des erreurs qui autrement planteraient le programme.
Une variable optionnelle peut contenir une valeur ou ne pas être
cas 1: var myVar:String? = "Something"
cas 2: var myVar:String? = nil
maintenant, si vous demandez à myVar !, vous demandez au compilateur de renvoyer une valeur dans le cas 1, il renverra "Something"
dans le cas 2, il va planter.
Sens ! mark obligera le compilateur à renvoyer une valeur, même si elle n’est pas présente. C’est pourquoi le nom Déballage forcé.
Si vous l'utilisez en option, il s'ouvre et indique s'il y a quelque chose. Si vous l'utilisez dans une instruction if-else, c'est un code pour NOT. Par exemple,
if (myNumber != 3){
// if myNumber is NOT 3 do whatever is inside these brackets.
)
Pour le dire simplement, les points d'exclamation signifient qu'un optionnel est en cours de déballage. Une option est une variable qui peut avoir une valeur ou non - vous pouvez donc vérifier si la variable est vide en utilisant une instruction if let comme indiqué ici , puis forcez-la à la dérouler. Si vous forcez le déballage d'un optionnel vide, votre programme va planter, alors faites attention! Les options sont déclarées en mettant un point d'interrogation à la fin d'une affectation explicite à une variable, par exemple, je pourrais écrire:
var optionalExample: String?
Cette variable n'a pas de valeur. Si je devais le déballer, le programme se bloquerait et Xcode vous dirait que vous aviez essayé de déballer une option avec une valeur nulle.
J'espère que ça a aidé.
IN SIMPLE WORDS
SING Le point d'exclamation indique que la variable doit être constituée d'une valeur non nulle (elle ne sera jamais nulle)
Toute l'histoire commence par Swift, une fonctionnalité appelée vars facultatifs. Ce sont les vars qui peuvent avoir une valeur ou ne pas avoir de valeur. En général, Swift ne nous permet pas d'utiliser une variable qui n'est pas initialisée, car cela peut entraîner des plantages ou des raisons inattendues, ainsi que de créer un espace réservé pour les portes dérobées. Ainsi, pour déclarer une variable dont la valeur n’a pas été déterminée initialement, nous utilisons un '?'. Lorsqu'une telle variable est déclarée, pour l'utiliser comme partie d'une expression, il faut la déballer avant son utilisation, le déballage est une opération par laquelle la valeur d'une variable est découverte et s'applique aux objets. Sans décompresser si vous essayez de les utiliser, vous aurez une erreur de compilation. Pour décompresser une variable qui est une variable facultative, le point d'exclamation "!" est utilisé.
Il arrive maintenant que vous sachiez que ces variables facultatives se verront attribuer des valeurs par le système, par exemple, ou ultérieurement par votre propre programme, par exemple les prises d'interface utilisateur, au lieu de déclarer une variable facultative à l'aide d'un point d'interrogation "?" nous utilisons "!".
Ainsi, le système sait que cette variable qui est déclarée avec "!" est optionnel pour le moment et n'a pas de valeur mais recevra une valeur plus tard dans sa vie.
Ainsi, le point d'exclamation a deux utilisations différentes: 1. Déclarer une variable qui sera optionnelle et recevra une valeur définitivement plus tard. 2. Déballer une variable optionnelle avant de l'utiliser dans une expression.
J'espère que les descriptions ci-dessus évitent trop de problèmes techniques.
John est une personne facultative, ce qui signifie qu'il peut avoir une valeur ou être nul.
john.apartment = number73
est utilisé si john n'est pas une option. Comme John n’est jamais nul, nous pouvons être sûrs qu’il n’appellera pas appartement avec une valeur nulle. Tandis que
john!.apartment = number73
promet au compilateur que john n'est pas nil, puis décompresse l'option permettant d'obtenir la valeur de john et accède à la propriété de john. Utilisez ceci si vous savez que john n'est pas nul. Si vous appelez cela facultativement avec nil, vous obtiendrez une erreur d'exécution.
La documentation inclut un exemple d'utilisation de Nice où convertNumber est facultatif.
if convertedNumber {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
Simple the Optional variable allows nil to be stored.
var str : String? = nil
str = "Data"
To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"
func get(message : String){
return
}
get(message : str!) // Unwapped to pass as String