Saya mencobanya untuk memahami hal penanganan kesalahan baru di swift 2. Inilah yang saya lakukan: Saya pertama kali menyatakan kesalahan enum:
enum SandwichError: ErrorType {
case NotMe
case DoItYourself
}
Dan kemudian saya menyatakan metode yang melempar kesalahan (tidak terkecuali orang. Ini adalah kesalahan.). Inilah metode itu:
func makeMeSandwich(names: [String: String]) throws -> String {
guard let sandwich = names["sandwich"] else {
throw SandwichError.NotMe
}
return sandwich
}
Masalahnya adalah dari sisi panggilan. Berikut adalah kode yang memanggil metode ini:
let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
}
Setelah do
baris kompiler mengatakan Errors thrown from here are not handled because the enclosing catch is not exhaustive
. Tapi menurut saya itu lengkap karena hanya ada dua kasus di SandwichError
enum.
Untuk laporan pergantian reguler, swift dapat memahaminya lengkap ketika setiap kasus ditangani.
do
blok di tingkat atas yang tidak lengkap - jika Anda membungkus do dalam fungsi non-lemparan, itu akan menghasilkan kesalahan.Jawaban:
Ada dua poin penting pada model penanganan kesalahan Swift 2: kelengkapan dan ketahanan. Bersama-sama, mereka direbus ke
do
/catch
pernyataan Anda perlu menangkap setiap kesalahan yang mungkin, bukan hanya yang Anda tahu Anda bisa melempar.Perhatikan bahwa Anda tidak menyatakan jenis kesalahan apa yang bisa dilempar suatu fungsi, hanya apakah itu benar-benar melempar. Ini adalah nol-satu-infinity masalah: sebagai seseorang yang mendefinisikan fungsi untuk orang lain (termasuk diri masa depan Anda) untuk digunakan, Anda tidak ingin harus membuat setiap klien fungsi Anda beradaptasi dengan setiap perubahan dalam implementasi Anda fungsi, termasuk kesalahan apa yang bisa dilemparkan. Anda ingin kode yang memanggil fungsi Anda tangguh terhadap perubahan tersebut.
Karena fungsi Anda tidak bisa mengatakan kesalahan apa yang dilemparkannya (atau mungkin terjadi di masa depan),
catch
blok yang menangkap kesalahan itu tidak tahu jenis kesalahan apa yang mungkin ditimbulkannya. Jadi, selain menangani jenis kesalahan yang Anda ketahui, Anda perlu menangani yang tidak Anda lakukan dengancatch
pernyataan universal - dengan cara itu jika fungsi Anda mengubah set kesalahan yang dilemparkannya di masa depan, penelepon masih akan menangkap kesalahannya. kesalahan.Tapi jangan berhenti di situ. Pikirkan lagi gagasan ketahanan ini. Cara Anda mendesain sandwich Anda, Anda harus menggambarkan kesalahan di setiap tempat Anda menggunakannya. Itu berarti bahwa setiap kali Anda mengubah set kasus kesalahan, Anda harus mengubah setiap tempat yang menggunakannya ... tidak terlalu menyenangkan.
Gagasan di balik mendefinisikan jenis kesalahan Anda sendiri adalah membiarkan Anda memusatkan hal-hal seperti itu. Anda dapat menentukan
description
metode untuk kesalahan Anda:Dan kemudian kode penanganan kesalahan Anda dapat meminta jenis kesalahan Anda untuk menggambarkan dirinya sendiri - sekarang setiap tempat di mana Anda menangani kesalahan dapat menggunakan kode yang sama, dan menangani kemungkinan kasus kesalahan yang akan datang juga.
Ini juga membuka jalan bagi tipe kesalahan (atau ekstensi pada mereka) untuk mendukung cara pelaporan kesalahan lainnya - misalnya, Anda bisa memiliki ekstensi pada jenis kesalahan Anda yang tahu bagaimana menyajikan a
UIAlertController
untuk melaporkan kesalahan kepada pengguna iOS.sumber
error caught in main()
.- Jadi sementara semua yang Anda katakan terdengar masuk akal, saya tidak dapat mereproduksi perilaku itu.try
ekspresi dalam kode produksi karena dapat menyebabkan kesalahan runtime dan menyebabkan aplikasi Anda macettry!
. Selain itu, ada kasus penggunaan yang valid dan "aman" untuk berbagai operasi "force" di Swift (buka, coba, dll.) Bahkan untuk kode produksi - jika melalui prakondisi atau konfigurasi Anda telah dengan andal menghilangkan kemungkinan kegagalan, itu bisa lebih masuk akal untuk hubungan pendek ke kegagalan instan daripada menulis kode penanganan kesalahan yang tidak dapat diuji.SandwichError
kelas masuk akal. Namun, saya menduga untuk sebagian besar kesalahan, logika penanganan kesalahan tidak dapat dienkapsulasi. Ini karena biasanya memerlukan pengetahuan tentang konteks penelepon (apakah untuk memulihkan, atau coba lagi, atau melaporkan kegagalan di bagian hulu, dll.). Dengan kata lain, saya menduga pola yang paling umum harus cocok dengan jenis kesalahan tertentu.Saya menduga ini belum diimplementasikan dengan benar. The Swift Pemrograman Panduan pasti tampaknya menyiratkan bahwa compiler dapat menyimpulkan pertandingan lengkap 'seperti pernyataan switch'. Itu tidak menyebutkan perlu jenderal
catch
agar lengkap.Anda juga akan melihat bahwa kesalahan ada di
try
baris, bukan di akhir blok, yaitu pada beberapa titik kompiler akan dapat menentukantry
pernyataan mana di blok yang memiliki jenis pengecualian yang tidak tertangani.Dokumentasinya agak ambigu. Saya telah membaca video 'Apa yang baru di Swift' dan tidak dapat menemukan petunjuk apa pun; Saya akan terus berusaha.
Memperbarui:
Kami sekarang hingga Beta 3 tanpa sedikit pun inferensi ErrorType. Saya sekarang percaya jika ini pernah direncanakan (dan saya masih berpikir itu pada titik tertentu), pengiriman dinamis pada ekstensi protokol mungkin mematikannya.
Pembaruan Beta 4:
Xcode 7b4 menambahkan dukungan komentar dokumen untuk
Throws:
, yang "harus digunakan untuk mendokumentasikan kesalahan apa yang dapat dilemparkan dan mengapa". Saya kira ini setidaknya menyediakan beberapa mekanisme untuk mengkomunikasikan kesalahan kepada konsumen API. Siapa yang butuh sistem tipe ketika Anda memiliki dokumentasi!Pembaruan lain:
Setelah menghabiskan beberapa waktu berharap untuk
ErrorType
kesimpulan otomatis , dan mencari tahu apa keterbatasan model itu, saya berubah pikiran - inilah yang saya harapkan dari Apple. Pada dasarnya:Namun Pembaruan Lainnya
Alasan penanganan kesalahan Apple sekarang tersedia di sini . Ada juga beberapa diskusi menarik tentang milis swift-evolution . Pada dasarnya, John McCall menentang kesalahan pengetikan karena dia yakin sebagian besar perpustakaan akan berakhir termasuk kasus kesalahan umum, dan bahwa kesalahan pengetikan tidak mungkin menambah banyak kode selain boilerplate (dia menggunakan istilah 'aspirational bluff'). Chris Lattner mengatakan dia terbuka untuk kesalahan pengetikan di Swift 3 jika itu dapat bekerja dengan model ketahanan.
sumber
Swift khawatir pernyataan kasus Anda tidak mencakup semua kasus, untuk memperbaikinya Anda harus membuat kasing default:
sumber
catch
pernyataan.func method() throws(YourErrorEnum)
, atau meskipunthrows(YourEnum.Error1, .Error2, .Error3)
begitu Anda tahu apa yang bisa dilemparkanSaya juga kecewa dengan kurangnya tipe fungsi yang bisa melempar, tapi saya mengerti sekarang berkat @rickster dan saya akan meringkasnya seperti ini: katakanlah kita dapat menentukan tipe yang dilempar fungsi, kita akan memiliki sesuatu seperti ini:
Masalahnya adalah bahkan jika kita tidak mengubah apa pun di myFunctionThatThrows, jika kita hanya menambahkan kasus kesalahan ke MyError:
kita kacau karena do / try / catch kita tidak lagi lengkap, serta tempat lain di mana kita memanggil fungsi yang melempar MyError
sumber
catch {}
di bagian bawah setiap blok bisa dibilang lebih buruk. Saya berharap kompiler pada akhirnya akan menyimpulkan jenis kesalahan secara otomatis di mana ia bisa tetapi saya belum dapat mengonfirmasi.Sekarang Nomor Validasi:
sumber
Buat enum seperti ini:
Buat metode seperti:
Sekarang periksa apakah ada kesalahan atau tidak dan tangani:
sumber