Sejak beta 8.3, zillions memperingatkan "Interpolasi string menghasilkan deskripsi debug untuk nilai opsional; apakah Anda bermaksud untuk membuatnya eksplisit?" muncul di kode saya.
Misalnya, peringatan muncul dalam situasi berikut, di mana opsi dapat mengarah ke nol:
let msg = "*** Error \(options["taskDescription"]): cannot load \(sUrl) \(error)"
Seperti yang dirancang sebelumnya, tidak masalah bagi saya (dan kompiler) opsional untuk diinterpolasi sebagai 'nil'. Tetapi compiler berubah pikiran.
Apa yang disarankan oleh compiler adalah menambahkan konstruktor String dengan deskripsi sebagai berikut:
let msg = "*** Error \(String(describing: options["taskDescription"])): cannot load \(sUrl) \(error)"
Jelas, hasilnya eksplisit tetapi juga menurut saya sangat tidak praktis. Apakah ada pilihan yang lebih baik? Apakah saya harus memperbaiki semua peringatan itu atau lebih baik menunggu beta berikutnya?
swift
swift3
optional
string-interpolation
Stéphane de Luca
sumber
sumber
Swift 3
merusak milik saya sendirilog
dan saya membuat kesalahan dengan hanya menggunakanprint
sebagai gantinya. Harus selalu membuat pembungkus Anda sendiri jika tidak Anda akan kacau oleh "fitur baru" semacam ini.Jawaban:
Ini adalah perubahan yang dibuat dalam permintaan tarik ini karena fakta bahwa interpolasi
Optional(...)
ke string resultan sering kali tidak diinginkan, dan bisa sangat mengejutkan dalam kasus dengan opsional yang tidak terbungkus secara implisit . Anda dapat melihat diskusi lengkap tentang perubahan ini di milis di sini .Seperti yang disebutkan dalam diskusi pull request (meskipun sayangnya bukan oleh Xcode) - satu cara yang sedikit lebih baik untuk membungkam peringatan daripada yang digunakan
String(describing:)
adalah dengan menambahkan cast ke tipe opsional dari apa pun yang Anda interpolasi, jadi misalnya: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
Yang juga bisa digeneralisasikan untuk
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
Di Swift 5, dengan sistem interpolasi string baru yang diperkenalkan oleh SE-0228 , opsi lainnya adalah menambahkan
appendInterpolation
kelebihan beban khusus untukDefaultStringInterpolation
: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
Dan, jika diinginkan, Anda bahkan dapat menghapus label argumen untuk menonaktifkan peringatan sepenuhnya di dalam modul (atau dalam file tertentu jika Anda menandainya sebagai
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
Meskipun secara pribadi saya lebih suka mempertahankan label argumen.
sumber
?? "nil"
membungkam peringatan, yang tampaknya agak populer, sehingga mungkin muncul di proposal lain dalam waktu dekat. Saya setuju bahwa solusi ini kurang dari ideal - secara pribadi, saya merasa agak jelas mengharapkanOptional(...)
untuk diinterpolasi ke dalam string untuk opsional yang kuat - hanya kasus IUO yang membutuhkan IMO peringatan ini. Tetapi Swift terus berkembang, jadi ini semua mungkin berubah di kemudian hari. Tapi untuk saat ini, itulah yang kami punya.guard result == nil else { print("result was \(result as Optional)") return }
if let
? misif let result = result { print("result was \(result)"); return }
. Tidak semua pengembalian awal harus dilakukan dengan penjaga.Dua cara yang lebih mudah untuk menangani masalah ini.
Pilihan 1:
Yang pertama adalah dengan "membuka paksa" nilai yang ingin Anda kembalikan menggunakan bang (!)
var someValue: Int? = 5 print(someValue!)
Keluaran:
5
Pilihan 2:
Cara lain, yang bisa menjadi cara yang lebih baik - adalah "membuka dengan aman" nilai yang ingin Anda kembalikan.
var someValue: Int? = 5 if let newValue = someValue { print(newValue) }
Keluaran:
5
Sarankan untuk pergi dengan opsi 2.
Tip: Hindari force unwrapping (!) Jika memungkinkan karena kami tidak yakin apakah kami akan selalu memiliki nilai yang akan dibuka.
sumber
tampaknya menggunakan String (menjelaskan: opsional) paling sederhana.
nilai default ?? tidak masuk akal untuk non-Strings misalnya Int.
Jika Int nil maka Anda ingin log yang menampilkan 'nil' bukan default ke Int lain misalnya 0.
Beberapa kode taman bermain untuk diuji:
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_)
Keluaran
optionalString: nil optionalInt: nil
sumber
Setelah memperbarui ke Xcode 8.3 dan mendapatkan banyak pesan peringatan, saya menemukan yang berikut ini yang lebih seperti perilaku keluaran asli, mudah ditambahkan, mengurangi penggunaan "String (menjelaskan :)" baik dalam kode maupun keluaran .
Pada dasarnya, tambahkan ekstensi Opsional yang memberikan String yang menjelaskan hal tersebut dalam opsional, atau cukup "nil" jika tidak disetel. Selain itu, jika yang ada di opsional adalah String, masukkan tanda kutip.
extension Optional { var orNil : String { if self == nil { return "nil" } if "\(Wrapped.self)" == "String" { return "\"\(self!)\"" } return "\(self!)" } }
Dan penggunaan di taman bermain:
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"
Terima kasih atas bantuan dari tautan berikut:
check-if-variable-is-an-optional-and-what-type-it-wraps
sumber
a?.b?.c.orNil
.Lihat perbaikan Ole Begeman untuk ini . Aku menyukainya. Ini menciptakan
???
operator yang kemudian dapat Anda gunakan seperti ini: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"
sumber
Klik dua kali pada segitiga kuning yang ditampilkan pada baris yang berisi peringatan ini. Ini akan menampilkan FixIt dengan dua solusi.
Menggunakan
String(describing:)
untuk membungkam peringatan ini:Menggunakan ini akan menjadi
String(describing:<Variable>)
Misalnya. :
String(describing: employeeName)
Sediakan sebuah
default value
untuk menghindari peringatan ini:Menggunakan ini akan menjadi
(<Variable> ?? default value)
Misalnya.:
employeeName ?? “Anonymous” as! String
sumber
Cepat 5
Solusi saya adalah membuat
extension
yang unwrapOptional
objek untukAny
.Saat Anda log objek atau mencetaknya, Anda dapat melihat aktual
object
atau<nil>⭕️
(kombinasi dari teks dan karakter visual). Ini berguna untuk dilihat, terutama di log konsol.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>|⭕️
sumber
Buat metode interpolasi yang menerima Jenis generik opsional dengan parameter tanpa nama. Semua peringatan Anda yang mengganggu akan hilang secara ajaib.
extension DefaultStringInterpolation { mutating func appendInterpolation<T>(_ optional: T?) { appendInterpolation(String(describing: optional)) } }
sumber