So lösen Sie: „Die String-Interpolation erzeugt eine Debug-Beschreibung für einen optionalen Wert. Wolltest du das explizit machen? “ in Xcode 8.3 Beta?

86

Seit Beta 8.3, zillionen Warnungen "String-Interpolation erzeugt eine Debug-Beschreibung für einen optionalen Wert; wollten Sie dies explizit machen?" erschien in meinem Code.

Beispielsweise wurde die Warnung in der folgenden Situation angezeigt, in der Optionen zu Null führen können:

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

Wie zuvor entworfen, war es für mich (und den Compiler) in Ordnung, die Optionen als 'Null' zu interpolieren. Aber der Compiler hat seine Meinung geändert.

Der Compiler schlägt vor, einen String-Konstruktor mit folgender Beschreibung hinzuzufügen:

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

Offensichtlich sind die Ergebnisse explizit, aber meiner Meinung nach auch sehr, sehr umständlich. Gibt es eine bessere Option? Muss ich all diese Warnungen korrigieren oder besser auf die nächste Beta warten?

Screenshot zur Beschreibung

Stéphane de Luca
quelle
25
Was für eine wirklich nervige Warnung ...
Jonny
Swift 3brach meine eigene logund ich machte einen Fehler, indem ich printstattdessen einfach benutzte . Sollte immer einen eigenen Wrapper erstellen, sonst werden Sie von dieser Art von "neuer Funktion" begeistert sein.
Superarts.org

Antworten:

104

Dies ist eine Änderung, die in dieser Pull-Anforderung vorgenommen wurde , da die Interpolation Optional(...)in die resultierende Zeichenfolge häufig unerwünscht ist und insbesondere in Fällen mit implizit entpackten Optionen überraschend sein kann . Die vollständige Diskussion dieser Änderung finden Sie auf der Mailingliste hier .

Wie in der Pull-Request-Diskussion erwähnt (obwohl leider nicht von Xcode) - eine etwas schönere Möglichkeit, die Warnung zum Schweigen zu bringen als die Verwendung von, String(describing:)besteht darin, dem optionalen Typ von allem, was Sie interpolieren, eine Besetzung hinzuzufügen, zum Beispiel:

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

Was auch verallgemeinert werden kann auf 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

In Swift 5 besteht eine weitere Option mit dem von SE-0228 eingeführten neuen String-Interpolationssystem darin, eine benutzerdefinierte appendInterpolationÜberladung hinzuzufügen für 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

Falls gewünscht, können Sie sogar die Argumentbezeichnung entfernen, um die Warnung vollständig innerhalb eines Moduls (oder innerhalb einer bestimmten Datei, wenn Sie sie als markieren fileprivate) zu deaktivieren :

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

Ich persönlich würde es jedoch vorziehen, das Argumentetikett beizubehalten.

Hamish
quelle
Aus dem Vorschlag geht nicht hervor, ob diese Änderung dauerhaft sein wird. Was denken Sie? @ Hamish
Stéphane de Luca
@ StéphanedeLuca Auf der Mailingliste gab es einige Diskussionen über andere Lösungen, z. B. das ?? "nil"Schweigen der Warnung, die sehr beliebt zu sein schien und daher in naher Zukunft in einem anderen Vorschlag auftauchen könnte. Ich bin damit einverstanden, dass diese Problemumgehung nicht ideal ist - ich persönlich halte es für ziemlich offensichtlich, dass Optional(...)für eine starke Option eine Interpolation in die Zeichenfolge erwartet wird - es war wirklich nur der Fall von IUOs, die diese Warnung IMO benötigten. Aber Swift entwickelt sich ständig weiter, so dass sich dies später ändern kann. Aber im Moment haben wir es.
Hamish
Ich bin auch auf ein etwas "verwandtes" Problem gestoßen, wenn ich hier nicht mehr auspacken darf. Stackoverflow.com/questions/42543512/… wenn Sie einen Blick darauf werfen können? @ Hamish
Stéphane de Luca
... auf jeden Fall ist dieser Code verrückt:guard result == nil else { print("result was \(result as Optional)") return }
loretoparisi
1
@loretoparisi Warum nicht verwenden if let? dh if let result = result { print("result was \(result)"); return }. Nicht alle vorzeitigen Rücksendungen müssen mit Wachen durchgeführt werden.
Hamish
28

Zwei einfachere Möglichkeiten, mit diesem Problem umzugehen.

Option 1:

Der erste wäre das "gewaltsame Auspacken" des Wertes, den Sie mit einem Knall (!) Zurückgeben möchten.

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

Ausgabe:

5

Option 2:

Der andere Weg, der der bessere sein könnte, besteht darin, den zurückgegebenen Wert "sicher auszupacken" .

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Ausgabe:

5

Würde empfehlen, mit Option 2 zu gehen.

Tipp: Vermeiden Sie nach Möglichkeit das gewaltsame Auspacken (!), Da wir nicht sicher sind, ob wir immer den Wert zum Auspacken haben werden.

Mo Iisa
quelle
1
Ich bin neu, aber ich mag die Option 2, um die Verpackung vor dem Drucken zu validieren, und Sie haben immer die Möglichkeit, etwas anderes zu drucken, wenn es ausgepackt ist
AbuTaareq
16

Die Verwendung von String (Beschreibung: optional) scheint am einfachsten zu sein.

Standardwert ?? macht keinen Sinn für Nicht-Strings, zB Int.
Wenn Int nil ist, soll im Protokoll 'nil' angezeigt werden, nicht standardmäßig ein anderes Int, z. B. 0.

Einige zu testende Spielplatzcodes:

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_)

Ausgabe

optionalString: nil
optionalInt: nil
brian.clear
quelle
13

Nach dem Update auf Xcode 8.3 und vielen Warnmeldungen habe ich Folgendes gefunden, das eher dem ursprünglichen Ausgabeverhalten ähnelt, das einfach hinzuzufügen ist und die Ausführlichkeit der Verwendung von "String (description :)" sowohl im Code als auch in der Ausgabe verringert .

Fügen Sie grundsätzlich eine optionale Erweiterung hinzu, die eine Zeichenfolge enthält, die das Element im optionalen Element beschreibt, oder einfach "nil", wenn sie nicht festgelegt ist. Wenn das optionale Element ein String ist, setzen Sie es in Anführungszeichen.

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

Und Verwendung auf einem Spielplatz:

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"

Vielen Dank für die Hilfe von folgendem Link:

Überprüfen Sie, ob die Variable eine optionale und welche Art von Wraps ist

anorskdev
quelle
Diese Lösung funktioniert nicht in einer optionalen Kette. Wie a?.b?.c.orNil.
Vincent Sit
11

Siehe Ole Begemans Fix dafür . Ich liebe es. Es wird ein ???Operator erstellt, den Sie dann folgendermaßen verwenden können:

var someValue: Int? = 5
print("The value is \(someValue ??? "unknown")")
// → "The value is 5"
someValue = nil
print("The value is \(someValue ??? "unknown")")
//"The value is unknown"
dar512
quelle
5
Ein Verweis auf seinen Blog-Beitrag, der dies beschreibt, wäre meiner Meinung nach nützlich: oleb.net/blog/2016/12/optionals-string-interpolation
Nicolai Henriksen
8

Doppelklicken Sie auf das gelbe Dreieck in der Zeile mit dieser Warnung. Dies zeigt FixIt mit zwei Lösungen.

Screenshot hinzugefügt

  1. Verwenden Sie String(describing:)diese Option , um diese Warnung zum Schweigen zu bringen:

    Mit diesem wird es werden String(describing:<Variable>)

    Z.B. ::String(describing: employeeName)

  2. Geben Sie a ein default value, um diese Warnung zu vermeiden:

    Mit diesem wird es werden (<Variable> ?? default value)

    Z.B.: employeeName ?? “Anonymous” as! String

Jayprakash Dubey
quelle
1
Ja, ich würde mich auch für den Nil-Coalescing-Operator entscheiden: developer.apple.com/library/content/documentation/Swift/…
kevinius
1
Gute Antwort! Nil-Coalescing funktioniert gut damit, wenn Sie einen alternativen Zeichenfolgenwert bereitstellen müssen
Lance Samaria
1

Swift 5

Meine Lösung besteht darin, ein Objekt zum extensionAuspacken Optionalzu erstellen Any.

Wenn Sie das Objekt protokollieren oder ausdrucken, können Sie das tatsächliche objectoder <nil>⭕️(Kombination aus Text und visuellem Zeichen) sehen. Dies ist besonders im Konsolenprotokoll hilfreich.

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
quelle
0

Erstellen Sie eine Interpolationsmethode, die einen optionalen generischen Typ mit einem unbenannten Parameter akzeptiert. Alle Ihre nervigen Warnungen werden auf magische Weise verschwinden.

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