web-dev-qa-db-fra.com

Swift: Test des options pour néant

J'utilise Xcode 6 Beta 4. J'ai cette situation étrange où je ne peux pas comprendre comment tester de manière appropriée les options.

Si j’ai un xyz en option, c’est la bonne façon de tester:

if (xyz) // Do something

ou

if (xyz != nil) // Do something

Les documents disent de le faire de la première façon, mais j'ai constaté que parfois, la deuxième est nécessaire et ne génère pas d'erreur de compilateur, mais d'autres fois, la deuxième génère une erreur de compilateur.

Mon exemple spécifique utilise l’analyseur XML GData ponté vers Swift:

let xml = GDataXMLDocument(
    XMLString: responseBody,
    options: 0,
    error: &xmlError);

if (xmlError != nil)

Ici, si je viens de le faire:

if xmlError

cela reviendrait toujours vrai. Cependant, si je le fais:

if (xmlError != nil)

alors cela fonctionne (comme cela fonctionne dans Objective-C).

Y at-il quelque chose avec le XML GData et la façon dont il traite les options que je manque?

118
tng

Dans Xcode Beta 5, ils ne vous permettent plus de faire:

var xyz : NSString?

if xyz {
  // Do something using `xyz`.
}

Cela produit une erreur:

n'est pas conforme au protocole 'BooleanType.Protocol'

Vous devez utiliser l'un de ces formulaires:

if xyz != nil {
   // Do something using `xyz`.
}

if let xy = xyz {
   // Do something using `xy`.
}
144
ktzhang

Pour ajouter aux autres réponses, au lieu d’affecter une variable de nom différent à l’intérieur d’une condition if:

var a: Int? = 5

if let b = a {
   // do something
}

vous pouvez réutiliser le même nom de variable comme ceci:

var a: Int? = 5

if let a = a {
    // do something
}

Cela pourrait vous aider à éviter de manquer de noms de variables créatives ...

Cela tire parti de observation variable qui est pris en charge dans Swift.

22
goggelj

L'une des manières les plus directes d'utiliser les options est la suivante:

En supposant que xyz soit de type facultatif, comme Int? par exemple.

if let possXYZ = xyz {
    // do something with possXYZ (the unwrapped value of xyz)
} else {
    // do something now that we know xyz is .None
}

De cette façon, vous pouvez tester si xyz contient une valeur et si c'est le cas, travailler immédiatement avec cette valeur.

En ce qui concerne votre erreur de compilation, le type UInt8 n'est pas optionnel (notez non '?') Et ne peut donc pas être converti en nil. Assurez-vous que la variable avec laquelle vous travaillez est une option avant de la traiter comme telle.

18
Isaac Drachman

Swift 3.0, 4.

Il existe principalement deux méthodes de vérification facultatives pour zéro. Voici des exemples de comparaison entre eux

1. Si laissé

if let est le moyen le plus simple de vérifier facultatif pour nil. D'autres conditions peuvent être ajoutées à cette vérification nulle, séparées par une virgule. La variable ne doit pas être nulle pour passer à la condition suivante. Si seule la vérification est requise, supprimez les conditions supplémentaires dans le code suivant.

En dehors de cela, si x n'est pas nul, la fermeture de if sera exécutée et x_val sera disponible à l'intérieur. Sinon, la fermeture de else est déclenchée.

if let x_val = x, x_val > 5 {
    //x_val available on this scope
} else {

}

2. Garde laisser

guard let peut faire la même chose. Son objectif principal est de le rendre logiquement plus raisonnable. C'est comme si on disait Assurez-vous que la variable n'est pas nulle, sinon arrêtez la fonction . guard let peut également effectuer une vérification de condition supplémentaire sous la forme if let.

Les différences sont que la valeur non enveloppée sera disponible sur la même portée que guard let, comme indiqué dans le commentaire ci-dessous. Cela conduit également au point que, en fermeture, le programme doit quitter la portée actuelle, par return, break, etc.

guard let x_val = x, x_val > 5 else {
    return
}
//x_val available on this scope
13
Fangming

De Swift programmation guide

Si instructions et décompression forcée

Vous pouvez utiliser une instruction if pour savoir si un facultatif contient une valeur. Si un facultatif a une valeur, sa valeur est true; s'il n'a aucune valeur, il est évalué à false.

Donc, la meilleure façon de faire est

// Swift > 3
if xyz != nil {}

et si vous utilisez la xyz dans l'instruction if.Than, vous pouvez décompresser xyz l'instruction if dans la variable constante. Vous n'avez donc pas besoin de décompresser chaque emplacement dans l'instruction if où xyz est utilisé.

if let yourConstant = xyz{
      //use youtConstant you do not need to unwrap `xyz`
}

Cette convention est suggérée par Apple et elle sera suivie par les développeurs.

10
codester

Bien que vous deviez toujours explicitement comparer une valeur optionnelle avec nil ou utiliser une liaison facultative pour extraire en plus sa valeur (c’est-à-dire que les options ne sont pas converties implicitement en valeurs booléennes), il convient de noter que Swift 2 a ajouté la valeur guard statement pour éviter la pyramide de Doom lorsque vous utilisez plusieurs valeurs facultatives.

En d'autres termes, vos options incluent désormais la vérification explicite de nil:

if xyz != nil {
    // Do something with xyz
}

Reliure optionnelle:

if let xyz = xyz {
    // Do something with xyz
    // (Note that we can reuse the same variable name)
}

Et guard instructions:

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    // e.g. by calling return, break, continue, or throw
    return
}

// Do something with xyz, which is now guaranteed to be non-nil

Notez comment une liaison facultative ordinaire peut entraîner une indentation plus grande lorsqu'il existe plusieurs valeurs facultatives:

if let abc = abc {
    if let xyz = xyz {
        // Do something with abc and xyz
    }        
}

Vous pouvez éviter cette imbrication avec les instructions guard:

guard let abc = abc else {
    // Handle failure and then exit this code block
    return
}

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    return
}

// Do something with abc and xyz
8
Chris Frederick

Au lieu de if, l'opérateur ternaire peut s'avérer utile lorsque vous souhaitez obtenir une valeur en fonction du caractère nul ou non:

func f(x: String?) -> String {
    return x == nil ? "empty" : "non-empty"
}
3
qed

Une autre approche en plus des instructions if ou guard pour effectuer la liaison facultative consiste à étendre Optional avec:

extension Optional {

    func ifValue(_ valueHandler: (Wrapped) -> Void) {
        switch self {
        case .some(let wrapped): valueHandler(wrapped)
        default: break
        }
    }

}

ifValue reçoit une fermeture et l'appelle avec la valeur en tant qu'argument lorsque facultatif n'est pas nul. Il est utilisé de cette façon:

var helloString: String? = "Hello, World!"

helloString.ifValue {
    print($0) // prints "Hello, World!"
}

helloString = nil

helloString.ifValue {
    print($0) // This code never runs
}

Vous devriez probablement utiliser un if ou guard cependant car ce sont les approches les plus conventionnelles (donc les plus familières) utilisées par les programmeurs Swift.

2
Tiago

Une option qui n'a pas été spécifiquement couverte consiste à utiliser la syntaxe de valeur ignorée de Swift:

if let _ = xyz {
    // something that should only happen if xyz is not nil
}

J'aime ça depuis que vérifier nil ne convient pas à une langue moderne comme Swift. Je pense que la raison pour laquelle il ne se sent pas à sa place est que nil est fondamentalement une valeur sentinelle. Nous avons supprimé les sentinelles un peu partout dans la programmation moderne, donc nil semble devoir aller aussi.

1
Ben Lachman

Maintenant vous pouvez faire dans Swift la chose suivante qui vous permet de retrouver un peu de l’objectif-c if nil else

if textfieldDate.text?.isEmpty ?? true {

}
0
Nicolas Manzini
var xyz : NSDictionary?

// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary() 
// case 3: do nothing

if xyz { NSLog("xyz is not nil.") }
else   { NSLog("xyz is nil.")     }

Ce test a fonctionné comme prévu dans tous les cas. Par ailleurs, vous n'avez pas besoin des crochets ().

0
Mundi

Si vous avez conditionnel et que vous souhaitez décompresser et comparer, que diriez-vous de tirer parti de l'évaluation en court-circuit de l'expression booléenne composée comme dans

if xyz != nil && xyz! == "some non-nil value" {

}

Certes, cela n'est pas aussi lisible que certains des autres postes suggérés, mais le travail est fait et un peu succinct par rapport aux autres solutions suggérées.

0
RT Denver

Extension du protocole Swift 5

Voici une approche utilisant une extension de protocole afin que vous puissiez facilement intégrer une vérification nil facultative:

 public extension Optional {

    var isNil: Bool {

        guard case Optional.none = self else {
            return false
        }

        return true

    }

}

tilisation

var myValue: String?

if !myValue.isNil {
    // do something
}
0
Brody Robertson

Aussi, vous pouvez utiliser Nil-Coalescing Operator

Le _nil-coalescing operator_ (_a ?? b_) décompresse un a facultatif s'il contient la valeur a ou renvoie a la valeur par défaut b si a est nil. L'expression a est toujours d'un type optionnel. L'expression b doit correspondre au type stocké dans a.

_let value = nullableValue ?? defaultValue
_

Si nullableValue est nil, il attribue automatiquement une valeur à defaultValue

0
yoAlex5