Come risolvere “L'interpolazione di stringhe produce una descrizione di debug per un valore opzionale; intendevi renderlo esplicito? " in Xcode 8.3 beta?


87

Dalla beta 8.3, milioni di avvertimenti "L'interpolazione di stringhe produce una descrizione di debug per un valore opzionale; intendevi renderlo esplicito?" è apparso nel mio codice.

Ad esempio, l'avviso è apparso nella seguente situazione, in cui le opzioni potrebbero portare a zero:

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

Come precedentemente progettato, andava bene per me (e per il compilatore) gli optionals da interpolare come 'nil'. Ma il compilatore ha cambiato idea.

Quello che suggerisce il compilatore è di aggiungere un costruttore String con la descrizione come segue:

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

Ovviamente il risultato è esplicito ma anche molto molto macchinoso secondo me. C'è un'opzione migliore? Devo correggere tutti quegli avvertimenti o meglio aspettare la prossima beta?

Screenshot per la descrizione


26
Che avvertimento davvero fastidioso ...
Jonny

Swift 3ha rotto il mio loge ho commesso un errore semplicemente usando printinvece. Dovresti sempre creare il tuo wrapper, altrimenti sarai fregato da questa sorta di "nuova funzionalità".
superarts.org

Risposte:


105

Questa è una modifica apportata a questa richiesta di pull poiché l'interpolazione Optional(...)nella stringa risultante è spesso indesiderabile e può essere particolarmente sorprendente nei casi con optionals implicitamente scartate . Puoi vedere la discussione completa di questa modifica sulla mailing list qui .

Come accennato nella discussione sulla richiesta pull (anche se sfortunatamente non da Xcode), un modo leggermente più carino per silenziare l'avviso rispetto all'uso di String(describing:)è aggiungere un cast al tipo opzionale di qualunque cosa tu stia interpolando, quindi per esempio:

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

Che può anche essere generalizzato a 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, con il nuovo sistema di interpolazione delle stringhe introdotto da SE-0228 , un'altra opzione è aggiungere un appendInterpolationsovraccarico personalizzato per 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

E, se lo desideri, puoi anche rimuovere l'etichetta dell'argomento per disabilitare l'avviso interamente all'interno di un modulo (o all'interno di un particolare file se lo contrassegni come 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

Anche se personalmente preferirei mantenere l'etichetta dell'argomento.


Dalla proposta non è chiaro se questo cambiamento sarà permanente? Cosa pensi? @Hamish
Stéphane de Luca

@ StéphanedeLuca C'è stata un bel po 'di discussione sulla mailing list su altre soluzioni come la possibilità ?? "nil"di mettere a tacere l'avvertimento, che sembrava essere leggermente popolare, quindi potrebbe apparire in un'altra proposta nel prossimo futuro. Sono d'accordo sul fatto che questa soluzione alternativa sia tutt'altro che ideale - personalmente, ritengo che sia piuttosto ovvio aspettarsi Optional(...)di essere interpolato nella stringa per un forte opzionale - era solo il caso degli IUO che avevano bisogno di questo avviso IMO. Ma Swift è in continua evoluzione, quindi tutto potrebbe cambiare in seguito. Ma per ora, è quello che abbiamo.
Hamish

Mi sono anche imbattuto in un problema in qualche modo "correlato" in un caso in cui non è più possibile unboxing qui stackoverflow.com/questions/42543512/… se puoi dare un'occhiata? @Hamish
Stéphane de Luca

... in ogni caso questo codice è una follia:guard result == nil else { print("result was \(result as Optional)") return }
loretoparisi

1
@loretoparisi Perché non usare if let? cioè if let result = result { print("result was \(result)"); return }. Non tutti i primi ritorni devono essere effettuati con le guardie.
Hamish

29

Due modi più semplici per affrontare questo problema.

Opzione 1:

Il primo sarebbe "scartando forzatamente" il valore che vorresti restituire usando un botto (!)

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

Produzione:

5

Opzione 2:

L'altro modo, che potrebbe essere il modo migliore, è "scartare in modo sicuro" il valore che desideri venga restituito.

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Produzione:

5

Consiglierei di andare con l'opzione 2.

Suggerimento: Evita di forzare lo scartamento (!) Ove possibile poiché non siamo sicuri se avremo sempre il valore per essere scartato.


1
Sono nuovo ma mi piace l'opzione 2 per convalidare l'avvolgimento prima della stampa e hai sempre la possibilità di stampare qualcos'altro quando viene scartato
AbuTaareq

16

sembra usare String (che descrive: opzionale) è più semplice.

valore predefinito ?? non ha senso per non-Strings, ad esempio Int.
Se Int è nil, allora vuoi che il log mostri 'nil' non di default su un altro Int es. 0.

Qualche codice di playground da testare:

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

Produzione

optionalString: nil
optionalInt: nil

13

Dopo l'aggiornamento a Xcode 8.3 e la ricezione di molti messaggi di avviso, ho trovato quanto segue che è più simile al comportamento dell'output originale, facile da aggiungere, riduce la verbosità dell'uso di "String (descinging :)" sia nel codice che nell'output .

Fondamentalmente, aggiungi un'estensione opzionale che fornisce una stringa che descrive la cosa nell'opzionale, o semplicemente "nil" se non impostata. Inoltre, se la cosa nell'opzionale è una stringa, inseriscila tra virgolette.

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

E l'utilizzo in un parco giochi:

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"

Grazie per l'aiuto dal seguente link:

controlla-se-la-variabile-è-un-opzionale-e-che-tipo-avvolge


Questa soluzione non funziona nella catena opzionale. Mi piace a?.b?.c.orNil.
Vincent Sit


8

Fare doppio clic sul triangolo giallo visualizzato sulla riga contenente questo avviso. Questo mostrerà FixIt con due soluzioni.

Screenshot aggiunto

  1. Utilizzare String(describing:)per silenziare questo avviso:

    Usando questo diventerà String(describing:<Variable>)

    Per esempio. :String(describing: employeeName)

  2. Fornire un default valueper evitare questo avviso:

    Usando questo diventerà (<Variable> ?? default value)

    Per esempio.: employeeName ?? “Anonymous” as! String


1
Sì, sceglierei anche l'operatore Nil-
Coalescing

1
Bella risposta! Nil-coalescing funziona bene con questo se hai un valore di stringa alternativo da fornire
Lance Samaria

1

Swift 5

La mia soluzione è creare un oggetto in extensioncui scartare .OptionalAny

Quando si registra l'oggetto o lo si stampa, è possibile visualizzare l'effettivo objecto <nil>⭕️(combinazione di testo e carattere visivo). È utile guardare, specialmente nel registro della 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>|⭕️

0

Creare un metodo di interpolazione che accetti un Type generico facoltativo con un parametro senza nome. Tutti i tuoi fastidiosi avvertimenti scompariranno magicamente.

extension DefaultStringInterpolation {
  mutating func appendInterpolation<T>(_ optional: T?) {
    appendInterpolation(String(describing: optional))
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.