Od wersji beta 8.3 zilliony ostrzeżeń „Interpolacja łańcuchów generuje opis debugowania dla wartości opcjonalnej; czy chodziło Ci o to, aby było to jawne?” pojawił się w moim kodzie.
Na przykład ostrzeżenie pojawiło się w następującej sytuacji, w której opcje mogą prowadzić do zera:
let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"
Zgodnie z wcześniejszym projektem, dla mnie (i dla kompilatora) opcje opcjonalne były w porządku interpolowane jako „zero”. Ale kompilator zmienił zdanie.
Kompilator sugeruje dodanie konstruktora typu String z następującym opisem:
let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"
Oczywiście wyniki są wyraźne, ale moim zdaniem również bardzo uciążliwe. Czy jest lepsza opcja? Czy muszę naprawić wszystkie te ostrzeżenia, czy lepiej poczekać na następną wersję beta?
swift
swift3
optional
string-interpolation
Stéphane de Luca
źródło
źródło
Swift 3
zepsułem własnelog
i popełniłem błąd, po prostu używającprint
zamiast tego. Powinieneś zawsze tworzyć własne opakowanie, w przeciwnym razie będziesz oszukiwany przez tego rodzaju „nową funkcję”.Odpowiedzi:
Jest to zmiana wprowadzona w tym żądaniu ściągnięcia ze względu na fakt, że interpolacja
Optional(...)
do wynikowego ciągu jest często niepożądana i może być szczególnie zaskakująca w przypadkach z niejawnie rozpakowanymi opcjami . Pełną dyskusję na temat tej zmiany możesz zobaczyć na liście mailingowej tutaj .Jak wspomniano w dyskusji o żądaniach ściągnięcia (chociaż niestety nie przez Xcode) - jednym nieco lepszym sposobem na wyciszenie ostrzeżenia niż użycie
String(describing:)
jest dodanie rzutowania do opcjonalnego typu tego, co interpolujesz, więc na przykład: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
Które można również uogólnić, aby
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
W Swift 5, z nowym systemem interpolacji ciągów wprowadzonym przez SE-0228 , inną opcją jest dodanie niestandardowego
appendInterpolation
przeciążenia dlaDefaultStringInterpolation
: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
W razie potrzeby możesz nawet usunąć etykietę argumentu, aby całkowicie wyłączyć ostrzeżenie w module (lub w określonym pliku, jeśli oznaczysz go jako
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
Chociaż osobiście wolałbym zachować etykietę argumentu.
źródło
?? "nil"
wyciszenia ostrzeżenia, które wydawało się być dość popularne, więc może pojawić się w innej propozycji w najbliższej przyszłości. Zgadzam się, że to obejście jest mniej niż idealne - osobiście uważam, że raczej oczywiste jest oczekiwanie,Optional(...)
że zostanie interpolowane do łańcucha dla silnego opcjonalnego - tak naprawdę tylko przypadek IUO wymagał tego ostrzeżenia IMO. Ale Swift stale się rozwija, więc to wszystko może się zmienić później. Ale na razie to właśnie mamy.guard result == nil else { print("result was \(result as Optional)") return }
if let
? tjif let result = result { print("result was \(result)"); return }
. Nie wszystkie wczesne powroty muszą odbywać się ze strażnikami.Dwa łatwiejsze sposoby rozwiązania tego problemu.
Opcja 1:
Pierwszym byłby „wymuszone rozpakowanie” wartości, którą chciałbyś zwrócić, używając huk (!)
var someValue: Int? = 5 print(someValue!)
Wynik:
5
Opcja 2:
Innym sposobem, który może być lepszym sposobem - jest „bezpieczne rozpakowanie” wartości, którą chcesz zwrócić.
var someValue: Int? = 5 if let newValue = someValue { print(newValue) }
Wynik:
5
Poleciłbym wybrać opcję 2.
Wskazówka: unikaj rozwijania na siłę (!), Jeśli to możliwe, ponieważ nie jesteśmy pewni, czy zawsze będziemy mieli wartość do rozpakowania.
źródło
Wydaje się, że użycie ciągu znaków (opis: opcjonalne) jest najprostsze.
domyślna wartość ?? nie ma sensu dla nie-łańcuchów, np. Int.
Jeśli Int jest nil, to chcesz, aby dziennik pokazywał 'nil', a nie domyślnie inny Int, np. 0.
Trochę kodu placu zabaw do przetestowania:
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_)
Wynik
optionalString: nil optionalInt: nil
źródło
Po aktualizacji do Xcode 8.3 i otrzymaniu wielu komunikatów ostrzegawczych, wymyśliłem następujące, które bardziej przypominają oryginalne zachowanie wyjściowe, są łatwe do dodania, zmniejszają gadatliwość używania „String (opisujący :)” zarówno w kodzie, jak i na wyjściu .
Zasadniczo dodaj opcjonalne rozszerzenie, które daje ciąg opisujący rzecz w opcjonalnym lub po prostu „nil”, jeśli nie jest ustawione. Ponadto, jeśli rzecz opcjonalna jest Stringiem, umieść ją w cudzysłowie.
extension Optional { var orNil : String { if self == nil { return "nil" } if "\(Wrapped.self)" == "String" { return "\"\(self!)\"" } return "\(self!)" } }
I zastosowanie na placu zabaw:
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"
Dzięki za pomoc z poniższego linku:
check-if-variable-is-an-optional-and-what-type-it-wrapaps
źródło
a?.b?.c.orNil
.Zobacz poprawkę Ole Begemana . Kocham to. Tworzy
???
operator, którego możesz następnie użyć w następujący sposób: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"
źródło
Kliknij dwukrotnie żółty trójkąt wyświetlany w wierszu zawierającym to ostrzeżenie. Spowoduje to wyświetlenie FixIt z dwoma rozwiązaniami.
Użyj,
String(describing:)
aby wyciszyć to ostrzeżenie:Używając tego, stanie się
String(describing:<Variable>)
Na przykład. :
String(describing: employeeName)
Podaj,
default value
aby uniknąć tego ostrzeżenia:Używając tego, stanie się
(<Variable> ?? default value)
Na przykład.:
employeeName ?? “Anonymous” as! String
źródło
Szybki 5
Moje rozwiązanie polega na utworzeniu obiektu, do
extension
którego należy rozpakować .Optional
Any
Kiedy logujesz obiekt lub drukujesz go, możesz zobaczyć rzeczywiste
object
or<nil>⭕️
(połączenie tekstu i znaku wizualnego). Warto się temu przyjrzeć, zwłaszcza w dzienniku konsoli.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>|⭕️
źródło
Utwórz metodę interpolacji, która akceptuje opcjonalny typ ogólny z nienazwanym parametrem. Wszystkie twoje irytujące ostrzeżenia magicznie znikną.
extension DefaultStringInterpolation { mutating func appendInterpolation<T>(_ optional: T?) { appendInterpolation(String(describing: optional)) } }
źródło