Qu'est-ce qu'un Facultatif (arrière-plan) ?
Dans Swift, une option est une constante ou une variable qui peut contenir une valeur OU aucune valeurnéant
du type d'origine. Cette valeur est notée "?". Une valeur facultative doit êtredéballé.
Donc, en d'autres termes, un facultatif est en fait unrécipientouemballage.
Le"!"
l'opérateur est unforcer le dérouleurqui expose ce qu'il y a dansrécipient. Il dit "croyez-moi, je sais ce que je fais, je sais que la valeur est là, la valeur n'est pas nulle" lorsque vous exécutez le code. Si vous vous trompezaccident.
A moins que tu ne sois vraimentsavoirque fais tu. Évitez d'utiliser le"!"
forcer l'opérateur de déballage. Probablement la principale cause de plantages pour les programmeurs Swift débutants.
Gérer les options (la pire façon)
Pourquoi ai-je reçu "Erreur fatale : zéro trouvé de manière inattendue lors du déballage d'une valeur facultative" ?
Vous avez probablement fait l'une des actions suivantes.
1. Déballage explicite de la force
Cela se fait avec le ! opérateur sur une option. Par exemple:
laisserchaîne facultative :Chaîne?imprimer(chaîne facultative !)// <- CRASH
Erreur fatale : Nil trouvé de manière inattendue lors du déballage d'une valeur facultative
Commechaîne facultative
estnéant
ici, vous obtiendrez un plantage sur la ligne où vous forcez à le déballer.
2. Options implicitement déballées
Ceux-ci sont définis avec un!
, Plutôt qu'un?
après le type.
étaitEntier facultatif :Int ! // cette valeur est implicitement désencapsulée partout où elle est utilisée
Ces options sont supposées contenir une valeur. Par conséquent, chaque fois que vous accédez à une option implicitement déballée, elle sera automatiquement déballée de force pour vous. S'il ne contient pas de valeur, il plantera.
imprimer(Entier facultatif)// <- CRASH
Erreur fatale : Nil trouvé de manière inattendue alors queimplicitementdéballage d'une valeur facultative
IBOutlets, sont souvent des options implicitement déballées. En effet, le xib ou le storyboard reliera les points de venteseulà l'exécution, après l'initialisation. Par conséquent, vous devez vous assurer que vous n'accédez pas aux prises avant qu'elles ne soient chargées en mémoire. Assurez-vous également que les connexions sont correctes dans votre storyboard ou fichier xib, sinon les valeurs serontnéant
lors de l'exécution, donc plantage lors de la première utilisation. Si vous essayez de corriger cette erreur (connexions), essayez de supprimer les lignes de code qui définissent vos points de vente, supprimez le lien du xib ou du storyboard s'il est toujours là, puis reconnectez-les.
Si vous voulez un commentaire de guide complet ci-dessous.
3. Lancements forcés (vers le bas)
laissermaChaîne = uneFormecomme!Chaîne
Ici, en forçant le casting, vous dites au compilateur de ne plus s'inquiéter, car vous aurez toujours unChaîne
exemple là. Et tant que cela tient, vous n'avez pas à vous inquiéter. Les problèmes commencent lorsque vous ou vos partenaires de code du projet commencez à faire circuler des valeurs non-String. Crash !!
4. Valeurs provenant d'Objective-C
Valeurs provenant d'Objective-C qui n'ont pas d'annotations de nullabilité. Supposons que nous ayons la classe Objective-C suivante :
@interfaceMonUtilisateur:NSObject@propriétéNSString*nom;@fin
Maintenant, si aucune annotation de nullabilité n'est spécifiée (soit explicitement, soit via NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END), alors la propriété name sera importée dans Swift en tant que chaîne ! (un IUO - facultatif implicitement déballé). Dès qu'un code Swift voudra utiliser la valeur, il plantera si name vaut nil.
Traiter en toute sécurité avec les options (la meilleure façon)
Solutions? Il existe de nombreuses façons de traiter les options qui sontplus sûr.
Swift est un langage de type sécurisé, ce qui signifie que le langage vous aide à être clair sur les types de valeurs avec lesquelles votre code peut fonctionner. Si une partie de votre code nécessite une chaîne, la sécurité de type vous empêche de lui transmettre un Int par erreur. De même, la sécurité de type vous empêche de transmettre accidentellement une chaîne facultative à un morceau de code qui nécessite une chaîne non facultative. La sécurité des types vous aide à détecter et à corriger les erreurs le plus tôt possible dans le processus de développement.
1. Reliure facultative
Cela vous permet de vérifier si une option contient une valeur et vous permet d'affecter la valeur non enveloppée à une nouvelle variable ou constante.
si laissernombre = entier facultatif {imprimer("Contient une valeur ! C'est \(nombre) !")}autre{imprimer("Ne contient pas de chiffre")}
Ce que cela fait, c'est d'abord vérifier que l'optionnel contient une valeur. Si c'est le cas, la valeur "déballée" est affectée à une nouvelle variable (nombre
) – que vous pouvez ensuite utiliser librement comme s'il n'était pas facultatif. Si l'optionnel ne contient pas de valeur, la clause else sera invoquée, comme vous vous en doutez.
Ce qui est bien avec la liaison facultative, c'est que vous pouvez déballer plusieurs options en même temps. Vous pouvez simplement séparer les déclarations par une virgule. L'instruction réussira si toutes les options ont été déballées.
étaitoptionnelInt :Int ?étaitanOptionalString :Chaîne?si laissernombre = entier facultatif,laissertext = anOptionalString {imprimer("optionalInt contient une valeur : \(nombre). Et il en va de même pour anOptionalString, c'est : \(texte)")}autre{imprimer("Une ou plusieurs des options ne contiennent pas de valeur")}
Une autre astuce intéressante est que vous pouvez également utiliser des virgules pour vérifier une certaine condition sur la valeur, après l'avoir déballée.
si laissernombre = optionnelInt, nombre >0{imprimer("optionalInt contient une valeur : \(nombre), et elle est supérieure à zéro !")}
Le seul problème avec l'utilisation d'une liaison facultative dans une instruction if est que vous ne pouvez accéder à la valeur non encapsulée qu'à partir de la portée de l'instruction. Si vous avez besoin d'accéder à la valeur depuis l'extérieur de la portée de l'instruction, vous pouvez utiliser une instruction de garde.
2. Déclaration de garde
Une instruction de garde vous permet de définir une condition de réussite - et la portée actuelle ne continuera à s'exécuter que si cette condition est remplie. Ils sont définis avec la syntaxecondition de garde sinon {...}
.
garde laissernombre = entier facultatifautre{retour}
Notez que dans le corps de garde, vous devez utiliser l'une des instructions de transfert de contrôle afin de sortir de la portée du code en cours d'exécution.
SiIntoptionnel
contient une valeur, elle sera déballée et affectée au nouveaunombre
constant. Le code après la garde continuera alors à s'exécuter. S'il ne contient pas de valeur, le gardien exécutera le code entre parenthèses, ce qui entraînera un transfert de contrôle, de sorte que le code immédiatement après ne sera pas exécuté.
La vraie chose intéressante à propos des instructions de garde est que la valeur non emballée est maintenant disponible pour être utilisée dans le code qui suit l'instruction (car nous savons que le futur code ne peut s'exécuter que si l'option a une valeur). C'est un excellent moyen d'éliminer les "pyramides de malheur" créées en imbriquant plusieurs instructions if.
garde laissernombre = entier facultatifautre{retour}imprimer("optionalInt contient une valeur, et c'est : \(nombre) !")
Les gardes prennent également en charge les mêmes astuces que l'instruction if, telles que le déballage de plusieurs options en même temps et l'utilisation de la clause where.
Que vous utilisiez une instruction if ou guard dépend entièrement du fait qu'un code futur nécessite que l'option contienne une valeur.
3. Chaînage optionnel
Vous pouvez utiliser le chaînage facultatif pour appeler une méthode ou accéder à une propriété facultative. Cela se fait simplement en suffixant le nom de la variable avec un?
lors de son utilisation.
Par exemple, supposons que nous ayons une variable foo, de type optionnelFoo
exemple.
étaittoto :Foo ?
Si nous voulions appeler une méthode surfou
qui ne retourne rien, on peut simplement faire :
foo?.doSomethingInteresting()
Si foo contient une valeur, cette méthode sera appelée dessus. Si ce n'est pas le cas, rien de grave ne se produira - le code continuera simplement à s'exécuter.
Ceci est similaire à l'envoi de messages à nil en Objective-C
Cela peut donc également être utilisé pour définir des propriétés ainsi que pour appeler des méthodes. Par exemple:
toto?.bar =Bar()
Encore une fois, rien de mal ne se passera ici sifou
estnéant
. Votre code continuera simplement à s'exécuter.
Une autre astuce que le chaînage facultatif vous permet de faire est de vérifier si la définition d'une propriété ou l'appel d'une méthode a réussi. Vous pouvez le faire en comparant la valeur de retour ànéant
.
C'est parce qu'une valeur facultative renverra
Annuler?
plutôt queAnnuler
sur une méthode qui ne retourne rien.
Exemple:
si(foo?.bar =Bar()) !=néant{imprimer("la barre a été définie avec succès")}autre{imprimer("la barre n'a pas été définie avec succès")}
4. Opérateur de coalescence nulle
L'opérateur de coalescence nulle est une version abrégée astucieuse de l'opérateur conditionnel ternaire, principalement conçu pour convertir les options en options non optionnelles. Il a la syntaxeun ?? b
, oùun
est un type facultatif etb
est du même genre queun
(bien que généralement non facultatif).
Il vous permet essentiellement de dire « Si a contient une valeur, déballez-la. Si ce n'est pas le cas, retournez b à la place ». Par exemple, vous pouvez l'utiliser comme ceci :
laissernombre = optionnelInt ??0
Cela définira unenombre
constante deInt
type, qui contiendra soit la valeur deIntoptionnel
, s'il contient une valeur, ou0
sinon.
C'est juste un raccourci pour:
laissernombre = optionnelInt !=néant? optionnelInt ! :0
Au revoir, C4