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?
swift
swift3
optional
string-interpolation
Stéphane de Luca
fuente
fuente
Swift 3
rompí el míolog
y cometí un error simplemente usando en suprint
lugar. Siempre debe crear su propio contenedor, de lo contrario, este tipo de "función nueva" le arruinará.Respuestas:
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
appendInterpolation
sobrecarga personalizada paraDefaultStringInterpolation
: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.
fuente
?? "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 esperarOptional(...)
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.guard result == nil else { print("result was \(result as Optional)") return }
if let
? es decirif let result = result { print("result was \(result)"); return }
. No todas las devoluciones anticipadas deben realizarse con guardias.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.
fuente
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
fuente
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
fuente
a?.b?.c.orNil
.Vea la solución de Ole Begeman para esto . Me encanta. Crea un
???
operador que luego puede usar así: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"
fuente
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.
Use
String(describing:)
para silenciar esta advertencia:Usando esto se convertirá en
String(describing:<Variable>)
P.ej. :
String(describing: employeeName)
Proporcione un
default value
para evitar esta advertencia:Usando esto se convertirá en
(<Variable> ?? default value)
P.ej.:
employeeName ?? “Anonymous” as! String
fuente
Rápido 5
Mi solución es hacer un objeto
extension
que desenvolver .Optional
Any
Cuando registra el objeto o lo imprime, puede ver el
object
o 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>|⭕️
fuente
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)) } }
fuente