Impression de la variable facultative


118

J'essaye avec ces lignes de code

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

Le code ci-dessus produit comme suit

Daniel hides his age.
Daniel is Optional(18) years old.

Ma question est de savoir pourquoi il y a facultatif (18) là-bas, comment puis-je supprimer l'option facultative et juste l'impression

Daniel is 18 years old.

Réponses:


190

Vous devez comprendre ce qu'est vraiment une option. De nombreux débutants Swift pensent var age: Int?que l'âge est un Int qui peut ou non avoir une valeur. Mais cela signifie que l'âge est une option qui peut ou non contenir un Int.

À l'intérieur de votre description()fonction, vous n'imprimez pas l'Int, mais à la place, vous imprimez l'Optionnel. Si vous souhaitez imprimer l'Int, vous devez dérouler l'Optionnel. Vous pouvez utiliser la "liaison facultative" pour dérouler une option:

if let a = age {
 // a is an Int
}

Si vous êtes sûr que l'Optionnel contient un objet, vous pouvez utiliser le "dépliage forcé":

let a = age!

Ou dans votre exemple, puisque vous avez déjà un test pour nil dans la fonction de description, vous pouvez simplement le changer en:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}

Je pense que l'exemple serait légèrement meilleur si vous le if let age = age { return ""} else { return "" }
kubi

13
+1 pour:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
lee

18

Un optionnel signifie que Swift n'est pas entièrement sûr si la valeur correspond au type: par exemple, Int? signifie que Swift n'est pas entièrement sûr que le nombre soit un Int.

Pour le supprimer, vous pouvez utiliser trois méthodes.

1) Si vous êtes absolument sûr du type, vous pouvez utiliser un point d'exclamation pour forcer le déballage, comme ceci:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Si vous forcez le déballage d'un optionnel et qu'il est égal à nil, vous pouvez rencontrer cette erreur de plantage:

entrez la description de l'image ici

Ce n'est pas forcément sûr, alors voici une méthode qui pourrait éviter de planter si vous n'êtes pas certain du type et de la valeur:

Les méthodes 2 et 3 protègent contre ce problème.

2) Le facultatif implicitement non emballé

 if let unwrappedAge = age {

 // continue in here

 }

Notez que le type non emballé est maintenant Int , plutôt que Int? .

3) La déclaration de garde

 guard let unwrappedAge = age else { 
   // continue in here
 }

De là, vous pouvez continuer et utiliser la variable non emballée. Assurez-vous de ne forcer le dépliage (avec un!) Que si vous êtes sûr du type de la variable.

Bonne chance pour votre projet!


1
en utilisant l'âge de retour! = nul? "(nom) a (âge!) ans." : "(nom) cache son âge."
leedream

1
M'a sauvé un mal de tête avec un problème que j'avais. Je ne peux pas vous remercier assez.
Bruno Recillas

8

À des fins de test / débogage, je souhaite souvent afficher des options sous forme de chaînes sans toujours avoir à tester les nilvaleurs, j'ai donc créé un opérateur personnalisé.

J'ai encore amélioré les choses après avoir lu cette réponse dans une autre question .

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

Évidemment, l'opérateur (et ses attributs) peut être modifié à votre guise, ou vous pouvez en faire une fonction à la place. Quoi qu'il en soit, cela vous permet d'écrire du code simple comme celui-ci:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

L'intégration de l'idée de protocole de l'autre gars a fait en sorte que cela fonctionne même avec des options imbriquées, qui se produisent souvent lors de l'utilisation du chaînage facultatif. Par exemple:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5

1
Depuis Swift 3, vous pouvez également utiliser la fonction de bibliothèque standard Swift debugPrint (_: separator: terminator :). Cela imprimera cependant la chaîne entre guillemets.
psmythirl

@psmythirl: Bon à savoir! Cependant, parfois, vous voudrez peut-être simplement passer ou incorporer un élément optionnel comme un Stringautre endroit (par exemple un journal / message d'erreur).
Jeremy

print (d as Any)
DawnSong

7

Mettre à jour

Utilisez simplement me.age ?? "Unknown age!". Cela fonctionne en 3.0.2.

Ancienne réponse

Sans déballage forcé (pas de signal mach / crash si nul), une autre bonne façon de faire cela serait:

(result["ip"] ?? "unavailable").description.

result["ip"] ?? "unavailable" devrait avoir du travail aussi, mais ce n'est pas le cas, pas en 2.2 du moins

Bien sûr, remplacez "indisponible" par ce qui vous convient: "nil", "not found" etc


4

Pour déballer une utilisation facultative à la age!place de age. Actuellement, vous imprimez une valeur facultative qui pourrait être nil. C'est pourquoi il s'est emballé avec Optional.


4

Dans swift Optionalest quelque chose qui peut être nildans certains cas. Si vous êtes sûr à 100% que a variableaura toujours une valeur et ne retournera pas nill'addition !avec la variable pour forcer le déroulement.

Dans les autres cas, si vous n'êtes pas très sûr de la valeur, ajoutez un if letbloc ou guardpour vous assurer que cette valeur existe, sinon cela peut entraîner un plantage.

Pour if letbloc:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

Pour guarddéclaration:

guard est une structure conditionnelle pour retourner le contrôle si la condition n'est pas remplie.

Je préfère utiliser guardover if letblock dans de nombreuses situations car cela nous permet de renvoyer le functionsi une valeur particulière n'existe pas. Comme quand il y a une fonction où une variable est intégrale pour exister, nous pouvons la vérifier dans une déclaration de garde et le retour de celle-ci n'existe pas. c'est à dire;

guard let abc = any_variable else { return }

Si la variable existe, nous pouvons utiliser 'abc' dans la fonction en dehors de la portée de garde.


3

ageest un type optionnel: Optional<Int>donc si vous le comparez à nil, il retourne false à chaque fois s'il a une valeur ou si ce n'est pas le cas. Vous devez dérouler l'option facultative pour obtenir la valeur.

Dans votre exemple, vous ne savez pas s'il contient une valeur, vous pouvez donc l'utiliser à la place:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}

3

J'ai fait cela pour imprimer la valeur de la chaîne (propriété) à partir d'un autre contrôleur de vue.

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

Résultat :

The Value of String is I am iOS Developer

2
Vous ne devriez pas forcer le déballage d'un optionnel
E-Riddie

3

Consultez la guarddéclaration:

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}

3

Lorsque vous avez une valeur par défaut:

print("\(name) is \(age ?? 0) years old")

ou lorsque le nom est facultatif:

print("\(name ?? "unknown") is \(age) years old")


1

J'obtenais l'option facultative ("chaîne") dans mes cellules de tableview.

La première réponse est excellente. Et m'a aidé à comprendre. Voici ce que j'ai fait, pour aider les recrues comme moi.

Puisque je crée un tableau dans mon objet personnalisé, je sais qu'il aura toujours des éléments en première position, donc je peux forcer le déplier dans une autre variable. Ensuite, utilisez cette variable pour imprimer, ou dans mon cas, définissez le texte de la cellule tableview.

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

Cela semble si simple maintenant, mais il m'a fallu un certain temps pour comprendre.


-1

Ce n'est pas la réponse exacte à cette question, mais une des raisons de ce genre de problème. Dans mon cas, je n'ai pas pu supprimer Optional d'une chaîne avec "if let" et "guard let".

Utilisez donc AnyObject au lieu de Any pour supprimer facultatif d'une chaîne dans swift.

Veuillez consulter le lien pour la réponse.

https://stackoverflow.com/a/51356716/8334818

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.