Cómo resolver “La interpolación de cadenas produce una descripción de depuración para un valor opcional; ¿Quisiste hacer esto explícito? " en Xcode 8.3 beta?

87

Desde la beta 8.3, millones de advertencias "La interpolación de cadenas produce una descripción de depuración para un valor opcional; ¿quiso hacer esto explícito?" apareció en mi código.

Por ejemplo, la advertencia apareció en la siguiente situación, donde las opciones podrían llevar a cero:

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

Como se diseñó anteriormente, estaba bien para mí (y el compilador) que los opcionales se interpolaran como 'nil'. Pero el compilador cambió de opinión.

Lo que sugiere el compilador es agregar un constructor de cadenas con una descripción de la siguiente manera:

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

Obviamente, los resultados son explícitos pero también muy, muy engorrosos en mi opinión. ¿Hay alguna opción mejor? ¿Tengo que arreglar todas esas advertencias o mejor esperar a la próxima beta?

Captura de pantalla para la descripción

Stéphane de Luca
fuente
26
Qué advertencia realmente molesta ...
Jonny
Swift 3rompí el mío logy cometí un error simplemente usando en su printlugar. Siempre debe crear su propio contenedor, de lo contrario, este tipo de "función nueva" le arruinará.
superarts.org

Respuestas:

105

Este es un cambio que se realizó en esta solicitud de extracción debido al hecho de que la interpolación Optional(...)en la cadena resultante a menudo no es deseable y puede ser especialmente sorprendente en casos con opciones opcionales implícitamente sin envolver . Puede ver la discusión completa de este cambio en la lista de correo aquí .

Como se mencionó en la discusión de la solicitud de extracción (aunque desafortunadamente no por Xcode), una forma un poco más agradable de silenciar la advertencia que el uso String(describing:)es agregar una conversión al tipo opcional de lo que sea que esté interpolando, por ejemplo:

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

Que también se puede generalizar 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

En Swift 5, con el nuevo sistema de interpolación de cadenas introducido por SE-0228 , otra opción es agregar una appendInterpolationsobrecarga personalizada para 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

Y, si lo desea, incluso puede eliminar la etiqueta del argumento para desactivar la advertencia por completo dentro de un módulo (o dentro de un archivo en particular si lo marca como 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

Aunque personalmente preferiría mantener la etiqueta del argumento.

Hamish
fuente
De la propuesta, ¿no queda claro si este cambio será permanente? ¿Qué piensas? @Hamish
Stéphane de Luca
@ StéphanedeLuca Hubo bastante discusión en la lista de correo sobre otras soluciones, como permitir ?? "nil"silenciar la advertencia, que parecía ser un poco popular, por lo que podría aparecer en otra propuesta en un futuro próximo. Estoy de acuerdo en que esta solución es menos que ideal; personalmente, creo que es bastante obvio esperar Optional(...)ser interpolado en la cadena para un opcional fuerte; solo fue realmente el caso de las IUO que necesitaban esta advertencia en mi opinión. Pero Swift está en constante evolución, por lo que todo esto puede cambiar más adelante. Pero por ahora, es lo que tenemos.
Hamish
También me encontré con un problema algo 'relacionado' en un si no lo desembalamos más aquí stackoverflow.com/questions/42543512/… si puedes echar un vistazo? @Hamish
Stéphane de Luca
... en cualquier caso este código es una guard result == nil else { print("result was \(result as Optional)") return }
locura
1
@loretoparisi ¿Por qué no usar if let? es decir if let result = result { print("result was \(result)"); return }. No todas las devoluciones anticipadas deben realizarse con guardias.
Hamish
29

Dos formas más sencillas de abordar este problema.

Opción 1:

La primera sería "desenvolver a la fuerza" el valor que le gustaría devolver usando un bang (!)

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

Salida:

5

Opcion 2:

La otra forma, que podría ser la mejor, es "desenvolver de forma segura" el valor que desea devolver.

var someValue: Int? = 5

if let newValue = someValue {
    print(newValue)
}

Salida:

5

Recomendaría ir con la opción 2.

Consejo: evite forzar el desenvolvimiento (!) Cuando sea posible, ya que no estamos seguros de si siempre tendremos el valor para desenvolver.

Mo Iisa
fuente
1
Soy nuevo, pero me gusta la opción 2 para validar el envoltorio antes de imprimir y siempre tiene la opción de imprimir algo más cuando está
desenvuelto
16

Parece que usar String (que describe: opcional) es lo más simple.

valor por defecto ?? no tiene sentido para no Strings, por ejemplo, Int.
Si Int es nil, entonces desea que el registro muestre 'nil', no predeterminado en otro Int, por ejemplo, 0.

Algunos códigos de juegos para probar:

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

Salida

optionalString: nil
optionalInt: nil
Brian.clear
fuente
13

Después de actualizar a Xcode 8.3 y recibir muchos mensajes de advertencia, se me ocurrió lo siguiente que se parece más al comportamiento de salida original, fácil de agregar, reduce la verbosidad de usar "String (describiendo :)" tanto en el código como en la salida .

Básicamente, agregue una extensión opcional que proporcione una cadena que describa la cosa en el opcional, o simplemente "nil" si no se establece. Además, si el elemento opcional es una cadena, colóquelo entre comillas.

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

Y uso en un parque infantil:

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"

Gracias por la ayuda del siguiente enlace:

comprobar-si-variable-es-opcional-y-qué-tipo-envuelve

anorskdev
fuente
Esta solución no funciona en cadena opcional. Al igual a?.b?.c.orNil.
Vincent Sit
8

Haga doble clic en el triángulo amarillo que se muestra en la línea que contiene esta advertencia. Esto mostrará FixIt con dos soluciones.

Captura de pantalla agregada

  1. Use String(describing:)para silenciar esta advertencia:

    Usando esto se convertirá en String(describing:<Variable>)

    P.ej. :String(describing: employeeName)

  2. Proporcione un default valuepara evitar esta advertencia:

    Usando esto se convertirá en (<Variable> ?? default value)

    P.ej.: employeeName ?? “Anonymous” as! String

Jayprakash Dubey
fuente
1
Sí, también optaría por el operador de coalescencia nula: developer.apple.com/library/content/documentation/Swift/…
kevinius
1
¡Gran respuesta! La fusión nula funciona bien con esto si tiene un valor de cadena alternativo para proporcionar
Lance Samaria
1

Rápido 5

Mi solución es hacer un objeto extensionque desenvolver .OptionalAny

Cuando registra el objeto o lo imprime, puede ver el objecto real <nil>⭕️(combinación de texto y carácter visual). Es útil mirarlo, especialmente en el registro de la consola.

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

Cree un método de interpolación que acepte un tipo genérico opcional con un parámetro sin nombre. Todas tus molestas advertencias desaparecerán mágicamente.

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