Comment résoudre «L'interpolation de chaîne produit une description de débogage pour une valeur facultative; vouliez-vous rendre cela explicite? » dans Xcode 8.3 beta?

87

Depuis la version bêta 8.3, zillions warnings "L'interpolation de chaîne produit une description de débogage pour une valeur facultative; vouliez-vous rendre cela explicite?" apparu dans mon code.

Par exemple, l'avertissement est apparu dans la situation suivante, où les options pouvaient conduire à zéro:

let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"

Comme précédemment conçu, il était normal pour moi (et le compilateur) d'interpoler les options comme «nil». Mais le compilateur a changé d'avis.

Ce que le compilateur suggère est d'ajouter un constructeur String avec la description suivante:

let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"

Evidemment, les résultats sont explicites mais aussi très très encombrants à mon avis. Y a-t-il une meilleure option? Dois-je corriger tous ces avertissements ou mieux attendre la prochaine version bêta?

Capture d'écran pour la description

Stéphane de Luca
la source
26
Quel avertissement vraiment ennuyeux ...
Jonny
Swift 3brisé le mien loget j'ai fait une erreur en utilisant simplement à la printplace. Devrait toujours créer votre propre wrapper sinon vous serez foutu par ce genre de "nouvelle fonctionnalité".
superarts.org

Réponses:

105

Il s'agit d'un changement qui a été apporté à cette demande d'extraction en raison du fait que l'interpolation Optional(...)dans la chaîne résultante est souvent indésirable, et peut être particulièrement surprenante dans les cas avec des options implicitement non emballées . Vous pouvez voir la discussion complète de ce changement sur la liste de diffusion ici .

Comme mentionné dans la discussion sur la demande d'extraction (bien que malheureusement pas par Xcode) - une façon légèrement plus agréable de faire taire l'avertissement que l'utilisation de String(describing:)consiste à ajouter un cast au type facultatif de tout ce que vous interpolez, par exemple:

var i: Int? = 5
var d: Double? = nil

print("description of i: \(i as Int?)")    // description of i: Optional(5)
print("description of d: \(d as Double?)") // description of d: nil

Ce qui peut également être généralisé à as Optional:

print("description of i: \(i as Optional)") // description of i: Optional(5)
print("description of d: \(d as Optional)") // description of d: nil

Dans Swift 5, avec le nouveau système d'interpolation de chaîne introduit par SE-0228 , une autre option consiste à ajouter une appendInterpolationsurcharge personnalisée pour DefaultStringInterpolation:

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}

var i: Int? = 5
var d: Double? = nil

print("description of i: \(optional: i)") // description of i: Optional(5)
print("description of d: \(optional: d)") // description of d: nil

Et, si vous le souhaitez, vous pouvez même supprimer l'étiquette d'argument pour désactiver l'avertissement entièrement dans un module (ou dans un fichier particulier si vous le marquez comme fileprivate):

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}

var i: Int? = 5
var d: Double? = nil

print("description of i: \(i)") // description of i: Optional(5)
print("description of d: \(d)") // description of d: nil

Bien que personnellement, je préfère garder l'étiquette d'argument.

Hamish
la source
D'après la proposition, il n'est pas clair si ce changement sera permanent? Qu'est-ce que tu penses? @Hamish
Stéphane de Luca
@ StéphanedeLuca Il y a eu pas mal de discussions sur la liste de diffusion sur d'autres solutions telles que permettre de ?? "nil"faire taire l'avertissement, qui semblait être légèrement populaire, donc pourrait apparaître dans une autre proposition dans un proche avenir. Je suis d'accord que cette solution de contournement est loin d'être idéale - personnellement, je pense qu'il est plutôt évident de s'attendre Optional(...)à être interpolé dans la chaîne pour un optionnel fort - ce n'était vraiment le cas des IUO qui avaient besoin de cet avertissement IMO. Mais Swift est en constante évolution, donc tout cela peut changer plus tard. Mais pour l'instant, c'est ce que nous avons.
Hamish
Je suis également tombé sur un problème quelque peu `` lié '' dans un si vous ne voulez plus déballer ici stackoverflow.com/questions/42543512/... si vous pouvez jeter un coup d'œil? @Hamish
Stéphane de Luca
... en tout cas ce code est de la folie:guard result == nil else { print("result was \(result as Optional)") return }
loretoparisi
1
@loretoparisi Pourquoi ne pas utiliser if let? ie if let result = result { print("result was \(result)"); return }. Tous les retours anticipés ne doivent pas être effectués avec des gardes.
Hamish
29

Deux moyens plus simples de traiter ce problème.

Option 1:

Le premier serait par "forcer le déballage" de la valeur que vous souhaitez renvoyer en utilisant un bang (!)

var someValue: Int? = 5
print(someValue!)

Production:

5

Option 2:

L'autre façon, qui pourrait être la meilleure, consiste à "déballer en toute sécurité" la valeur que vous souhaitez renvoyer.

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Production:

5

Je recommanderais d'aller avec l'option 2.

Conseil: évitez le déballage forcé (!) Lorsque cela est possible car nous ne savons pas si nous aurons toujours la valeur à déballer.

Mo Iisa
la source
1
Je suis nouveau mais j'aime l'option 2 pour valider l'emballage avant impression et vous avez toujours une option pour imprimer autre chose quand il est déballé
AbuTaareq
16

semble utiliser String (décrivant: facultatif) est le plus simple.

valeur par défaut ?? n'a aucun sens pour les non-chaînes, par exemple Int.
Si Int est nul, vous voulez que le journal affiche «nil» et non par défaut un autre Int, par exemple 0.

Quelques codes de jeux à tester:

var optionalString : String? = nil
var optionalInt : Int? = nil

var description_ = ""
description_ = description_ + "optionalString: \(String(describing: optionalString))\r"
description_ = description_ + "   optionalInt: \(String(describing: optionalInt))\r"

print(description_)

Production

optionalString: nil
optionalInt: nil
brian.clear
la source
13

Après la mise à jour vers Xcode 8.3 et avoir reçu de nombreux messages d'avertissement, j'ai proposé ce qui suit qui ressemble plus au comportement de sortie d'origine, facile à ajouter, réduit la verbosité de l'utilisation de "String (décrivant :)" à la fois dans le code et la sortie .

Fondamentalement, ajoutez une extension facultative qui donne une chaîne décrivant la chose dans l'option facultative, ou simplement «nil» si elle n'est pas définie. De plus, si l'élément facultatif est une chaîne, mettez-le entre guillemets.

extension Optional {
    var orNil : String {
        if self == nil {
            return "nil"
        }
        if "\(Wrapped.self)" == "String" {
            return "\"\(self!)\""
        }
        return "\(self!)"
    }
}

Et utilisation dans une aire de jeux:

var s : String?
var i : Int?
var d : Double?

var mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = nil    i = nil   d = nil"

d = 3
i = 5
s = ""
mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = ""    i = 5   d = 3.0"

s = "Test"
d = nil
mixed = "s = \(s.orNil)    i = \(i.orNil)   d = \(d.orNil)" // "s = "Test"    i = 5   d = nil"

Merci pour l'aide du lien suivant:

vérifier-si-la-variable-est-une-option-et-quel-type-elle-enveloppe

anorskdev
la source
Cette solution ne fonctionne pas en chaîne optionnelle. Comme a?.b?.c.orNil.
Vincent Sit
8

Double-cliquez sur le triangle jaune affiché sur la ligne contenant cet avertissement. Cela montrera FixIt avec deux solutions.

Capture d'écran ajoutée

  1. Utilisation String(describing:) pour faire taire cet avertissement:

    En utilisant cela, il deviendra String(describing:<Variable>)

    Par exemple. :String(describing: employeeName)

  2. Fournir un default value pour éviter cet avertissement:

    En utilisant cela, il deviendra (<Variable> ?? default value)

    Par exemple.: employeeName ?? “Anonymous” as! String

Jayprakash Dubey
la source
1
Oui, j'irais aussi pour l'opérateur Nil-Coalescing: developer.apple.com/library/content/documentation/Swift
...
1
Très bonne réponse! Nil-coalescing fonctionne bien avec ceci si vous avez une valeur de chaîne alternative à fournir
Lance Samaria
1

Swift 5

Ma solution consiste à créer un objet sur extensionlequel déballer .OptionalAny

Lorsque vous connectez l'objet ou que vous l'imprimez, vous pouvez voir le objectou <nil>⭕️(combinaison du texte et du caractère visuel). Il est utile de regarder, en particulier dans le journal de la console.

extension Optional {
    var logable: Any {
        switch self {
        case .none:
            return "<nil>|⭕️"
        case let .some(value):
            return value
        }
    }
}

// sample
var x: Int?
print("Logging optional without warning: \(x.logable)")
// → Logging optional without warning: <nil>|⭕️
nahung89
la source
0

Créez une méthode d'interpolation qui accepte un type générique facultatif avec un paramètre sans nom. Tous vos avertissements ennuyeux disparaîtront comme par magie.

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}
ScottyBlades
la source