Desde o beta 8.3, zilhões de avisos "A interpolação de strings produz uma descrição de depuração para um valor opcional; você pretendia tornar isso explícito?" apareceu no meu código.
Por exemplo, o aviso apareceu na seguinte situação, em que as opções podem levar a zero:
let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"
Conforme projetado anteriormente, estava tudo bem para mim (e para o compilador) que os opcionais fossem interpolados como 'nulo'. Mas o compilador mudou de ideia.
O que o compilador sugere é adicionar um construtor String com a descrição a seguir:
let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"
Obviamente, os resultados são explícitos, mas também muito complicados na minha opinião. Existe uma opção melhor? Tenho que corrigir todos esses avisos ou melhor esperar pelo próximo beta?
swift
swift3
optional
string-interpolation
Stéphane de Luca
fonte
fonte
Swift 3
quebrou o meu própriolog
e cometi um erro ao simplesmente usarprint
. Deve sempre criar seu próprio invólucro, caso contrário você ficará confuso com esse tipo de "novo recurso".Respostas:
Esta é uma alteração que foi feita nesta solicitação de pull devido ao fato de que a interpolação
Optional(...)
na string resultante é frequentemente indesejável e pode ser especialmente surpreendente em casos com opcionais não embalados implicitamente . Você pode ver a discussão completa sobre essa mudança na lista de discussão aqui .Conforme mencionado na discussão de solicitação pull (embora infelizmente não seja pelo Xcode) - uma maneira um pouco melhor de silenciar o aviso do que o uso de
String(describing:)
é adicionar um elenco ao tipo opcional de tudo o que você está interpolando, por exemplo: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 também pode ser generalizado para
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
No Swift 5, com o novo sistema de interpolação de string introduzido por SE-0228 , outra opção é adicionar uma
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
E, se desejar, você pode até mesmo remover o rótulo do argumento para desativar o aviso inteiramente em um módulo (ou em um arquivo específico, se você marcá-lo 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
Embora pessoalmente eu prefira manter o rótulo do argumento.
fonte
?? "nil"
silenciar o aviso, que parecia ser ligeiramente popular, por isso pode aparecer em outra proposta no futuro próximo. Eu concordo que essa solução alternativa é menos do que ideal - pessoalmente, acho que é bastante óbvio esperarOptional(...)
ser interpolado na string para um opcional forte - era apenas o caso de IUOs que precisavam desse aviso IMO. Mas o Swift está em constante evolução, então tudo isso pode mudar mais tarde. Mas, por enquanto, é o que temos.guard result == nil else { print("result was \(result as Optional)") return }
if let
? ieif let result = result { print("result was \(result)"); return }
. Nem todos os retornos antecipados precisam ser feitos com guardas.Duas maneiras mais fáceis de lidar com esse problema.
Opção 1:
A primeira seria "desembrulhar à força" o valor que você gostaria de retornar usando um estrondo (!)
var someValue: Int? = 5 print(someValue!)
Resultado:
5
Opção 2:
A outra forma, que poderia ser a melhor - é "desembrulhar com segurança" o valor que você deseja que seja retornado.
var someValue: Int? = 5 if let newValue = someValue { print(newValue) }
Resultado:
5
Recomendaria ir com a opção 2.
Dica: Evite forçar o desempacotamento (!) Sempre que possível, pois não temos certeza se sempre teremos o valor a ser desembrulhado.
fonte
parece usar String (descrevendo: opcional) é mais simples.
valor padrão ?? não faz sentido para não Strings, por exemplo, Int.
Se Int for nulo, então você deseja que o log mostre 'nil' e não o padrão para outro Int, por exemplo, 0.
Alguns códigos de playground para testar:
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_)
Resultado
optionalString: nil optionalInt: nil
fonte
Depois de atualizar para o Xcode 8.3 e receber muitas mensagens de aviso, eu vim com o seguinte que é mais parecido com o comportamento de saída original, fácil de adicionar, reduz o detalhamento do uso de "String (descrevendo :)" tanto no código quanto na saída .
Basicamente, adicione uma extensão opcional que forneça uma string descrevendo a coisa no opcional, ou simplesmente "nil" se não for definida. Além disso, se o item opcional for uma String, coloque-o entre aspas.
extension Optional { var orNil : String { if self == nil { return "nil" } if "\(Wrapped.self)" == "String" { return "\"\(self!)\"" } return "\(self!)" } }
E uso em um playground:
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"
Obrigado pela ajuda no seguinte link:
check-if-variable-is-an-optional-and-what-type-it-wraps
fonte
a?.b?.c.orNil
.Veja a correção de Ole Begeman para isso . Eu amo isso. Ele cria um
???
operador que você pode usar assim: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"
fonte
Clique duas vezes no triângulo amarelo exibido na linha que contém este aviso. Isso mostrará FixIt com duas soluções.
Use
String(describing:)
para silenciar este aviso:Usando isso, ele se tornará
String(describing:<Variable>)
Por exemplo. :
String(describing: employeeName)
Forneça um
default value
para evitar este aviso:Usando isso, ele se tornará
(<Variable> ?? default value)
Por exemplo.:
employeeName ?? “Anonymous” as! String
fonte
Swift 5
Minha solução é fazer um objeto
extension
que desembrulhe .Optional
Any
Quando você registra o objeto ou imprime-o, você pode ver o real
object
ou<nil>⭕️
(combinação de texto e caráter visual). É útil olhar, especialmente no log do 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>|⭕️
fonte
Crie um método de interpolação que aceite um Type genérico opcional com um parâmetro sem nome. Todos os seus avisos irritantes irão desaparecer magicamente.
extension DefaultStringInterpolation { mutating func appendInterpolation<T>(_ optional: T?) { appendInterpolation(String(describing: optional)) } }
fonte