Sebelum saya dapat menjelaskan kasus penggunaan untuk Opsional Unwrapped Secara Implisit, Anda harus sudah memahami apa Optional dan Oppt Unwrapped secara implisit di Swift. Jika tidak, saya sarankan Anda terlebih dahulu membaca artikel saya tentang opsional
Kapan Harus Menggunakan Pilihan yang Tidak Dibungkus Secara Opsional
Ada dua alasan utama bahwa seseorang akan membuat Opsional Unwrapped Opsional. Semua harus dilakukan dengan mendefinisikan variabel yang tidak akan pernah diakses ketika nil
karena jika tidak, kompiler Swift akan selalu memaksa Anda untuk secara eksplisit membuka Bungkusan Opsional.
1. Konstan Yang Tidak Dapat Didefinisikan Selama Inisialisasi
Setiap konstanta anggota harus memiliki nilai pada saat inisialisasi selesai. Kadang-kadang, konstanta tidak dapat diinisialisasi dengan nilai yang benar selama inisialisasi, tetapi masih dapat dijamin memiliki nilai sebelum diakses.
Menggunakan variabel Opsional mengatasi masalah ini karena Opsional secara otomatis diinisialisasi dengan nil
dan nilai yang nantinya akan berisi akan tetap tidak berubah. Namun, bisa jadi menyakitkan untuk terus membuka bungkus variabel yang Anda tahu pasti tidak nol. Opsional Unwrapped secara implisit mencapai manfaat yang sama dengan Opsional dengan manfaat tambahan yang tidak harus secara eksplisit dibuka di mana-mana.
Contoh yang bagus dari ini adalah ketika variabel anggota tidak dapat diinisialisasi dalam subkelas UIView hingga tampilan dimuat:
class MyView: UIView {
@IBOutlet var button: UIButton!
var buttonOriginalWidth: CGFloat!
override func awakeFromNib() {
self.buttonOriginalWidth = self.button.frame.size.width
}
}
Di sini, Anda tidak dapat menghitung lebar asli tombol hingga tampilan dimuat, tetapi Anda tahu itu awakeFromNib
akan dipanggil sebelum metode lain apa pun pada tampilan (selain inisialisasi). Alih-alih memaksa nilai untuk secara terbuka terbuka secara tidak ada gunanya di seluruh kelas Anda, Anda dapat mendeklarasikannya sebagai Pilihan yang Tidak Dibungkus Secara Implisit.
2. Ketika Aplikasi Anda Tidak Dapat Sembuh Dari Makhluk Bervariasi nil
Ini seharusnya sangat jarang, tetapi jika aplikasi Anda tidak dapat terus berjalan jika suatu variabel nil
saat diakses, itu akan membuang-buang waktu untuk mengujinya nil
. Biasanya jika Anda memiliki kondisi yang pasti benar untuk aplikasi Anda untuk terus berjalan, Anda akan menggunakan assert
. Opsional Unwrapped Implisit memiliki pernyataan untuk nil dibangun langsung ke dalamnya. Meski begitu, sering kali baik untuk membuka bungkusan opsional dan menggunakan pernyataan yang lebih deskriptif jika nihil.
Ketika Tidak Menggunakan Opsional Unwrapped Secara implisit
1. Variabel Anggota Terhitung yang Dihitung
Kadang-kadang Anda memiliki variabel anggota yang tidak boleh nol, tetapi tidak dapat ditetapkan ke nilai yang benar selama inisialisasi. Salah satu solusinya adalah dengan menggunakan Opsional Unwrapped Opsional, tetapi cara yang lebih baik adalah dengan menggunakan variabel malas:
class FileSystemItem {
}
class Directory : FileSystemItem {
lazy var contents : [FileSystemItem] = {
var loadedContents = [FileSystemItem]()
// load contents and append to loadedContents
return loadedContents
}()
}
Sekarang, variabel anggota contents
tidak diinisialisasi sampai pertama kali diakses. Ini memberi kelas kesempatan untuk masuk ke keadaan yang benar sebelum menghitung nilai awal.
Catatan: Ini sepertinya bertentangan dengan # 1 dari atas. Namun, ada perbedaan penting yang harus dibuat. Di buttonOriginalWidth
atas harus ditetapkan selama viewDidLoad untuk mencegah siapa pun mengubah lebar tombol sebelum properti diakses.
2. Di Tempat Lain
Untuk sebagian besar, Opsional Unwrapped Opsional harus dihindari karena jika digunakan secara salah, seluruh aplikasi Anda akan macet ketika diakses sementara nil
. Jika Anda tidak pernah yakin tentang apakah suatu variabel dapat nol, selalu default untuk menggunakan Opsional normal. Membuka gulungan variabel yang tidak pernah nil
tentu tidak terlalu menyakitkan.
if someOptional
.hasValue
didefinisikan tepat di Opsional. Saya lebih suka semantikhasValue
untuk yang dari!= nil
. Saya merasa itu jauh lebih dimengerti untuk programmer baru yang belum menggunakannil
bahasa lain.hasValue
jauh lebih logis daripadanil
.hasValue
ditarik dari beta 6. Ash memasukkannya kembali ... github.com/AshFurrow/hasValueOpsinya yang tidak dibungkus secara implisit berguna untuk menghadirkan properti sebagai tidak-opsional ketika benar-benar harus opsional di bawah penutup. Ini sering diperlukan untuk "mengikat simpul" antara dua objek terkait yang masing-masing memerlukan referensi ke yang lain. Masuk akal bila tidak ada referensi yang benar - benar opsional, tetapi salah satunya harus nol saat pasangan diinisialisasi.
Sebagai contoh:
Setiap
B
instance harus selalu memilikimyBuddyA
referensi yang valid , jadi kami tidak ingin membuat pengguna memperlakukannya sebagai opsional, tetapi kami membutuhkannya menjadi opsional sehingga kami dapat membuatB
sebelum kita memilikiA
untuk merujuk.NAMUN! Persyaratan referensi timbal balik semacam ini sering merupakan indikasi kopling ketat dan desain yang buruk. Jika Anda mendapati diri Anda bergantung pada opsi yang secara implisit tidak terbuka, Anda mungkin harus mempertimbangkan refactoring untuk menghilangkan ketergantungan-silang.
sumber
@IBOutlet
weak
deklarasi dan menghapus "tanpa menciptakan siklus mempertahankan kuat"Opsinya yang tidak terbuka secara implisit adalah kompromi pragmatis untuk membuat pekerjaan di lingkungan hybrid yang harus beroperasi dengan kerangka kerja Kakao yang ada dan konvensi mereka lebih menyenangkan, sementara juga memungkinkan migrasi bertahap ke dalam paradigma pemrograman yang lebih aman - tanpa penunjuk nol - ditegakkan oleh kompiler Swift.
Buku Swift, dalam bab Dasar-Dasar , bagian Opsional Unwrapped Implisit mengatakan:
Ini datang ke menggunakan kasus di mana non
nil
-ness properti didirikan melalui konvensi penggunaan, dan tidak bisa ditegakkan oleh compiler selama inisialisasi kelas. Misalnya,UIViewController
properti yang diinisialisasi dari NIB atau Storyboards, di mana inisialisasi dibagi menjadi fase terpisah, tetapi setelahviewDidLoad()
Anda dapat mengasumsikan bahwa properti secara umum ada. Kalau tidak, untuk memenuhi kompiler, Anda harus menggunakan pembungkusan paksa , pengikatan opsional atau rantai opsional hanya untuk mengaburkan tujuan utama kode.Di atas bagian dari buku Swift merujuk juga ke bab Penghitungan Referensi Otomatis :
Ini datang ke keunikan karena tidak menjadi bahasa sampah yang dikumpulkan, oleh karena itu mematahkan siklus tetap ada pada Anda sebagai seorang programmer dan opsional yang secara terbuka membuka alat untuk menyembunyikan kekhasan ini.
Itu mencakup "Kapan harus menggunakan opsional yang secara terbuka tidak terbungkus dalam kode Anda?" pertanyaan. Sebagai pengembang aplikasi, sebagian besar Anda akan menemukannya dalam tanda tangan metode perpustakaan yang ditulis dalam Objective-C, yang tidak memiliki kemampuan untuk mengekspresikan jenis opsional.
Dari Menggunakan Swift dengan Cocoa dan Objective-C, bagian Bekerja dengan nihil :
... dan di luar sini berbaring
sumber
Contoh sederhana satu baris (atau beberapa baris) tidak mencakup perilaku opsional dengan sangat baik - ya, jika Anda mendeklarasikan variabel dan segera memberikan nilai, tidak ada gunanya opsional.
Kasus terbaik yang pernah saya lihat sejauh ini adalah pengaturan yang terjadi setelah inisialisasi objek, diikuti dengan penggunaan yang "dijamin" untuk mengikuti pengaturan itu, misalnya dalam pengontrol tampilan:
Kami tahu
printSize
akan dipanggil setelah tampilan dimuat - ini adalah metode tindakan yang terhubung ke kontrol di dalam tampilan itu, dan kami memastikan untuk tidak menyebutnya sebaliknya. Jadi kita bisa menghemat beberapa pemeriksaan-opsional / mengikat dengan!
. Swift tidak dapat mengenali jaminan itu (setidaknya sampai Apple menyelesaikan masalah penghentian), jadi Anda memberi tahu kompilator bahwa itu ada.Ini memecah keamanan jenis sampai tingkat tertentu. Di mana pun Anda memiliki opsi yang secara terbuka tidak tersirat adalah tempat aplikasi Anda bisa mogok jika "jaminan" Anda tidak selalu berlaku, jadi ini adalah fitur yang harus digunakan dengan hemat. Selain itu, menggunakan
!
sepanjang waktu membuatnya terdengar seperti Anda berteriak, dan tidak ada yang suka itu.sumber
CGSizeZero
bisa menjadi nilai sentinel yang baik dalam penggunaan di dunia nyata. Tetapi bagaimana jika Anda memiliki ukuran yang dimuat dari nib yang mungkin sebenarnya nol? Kemudian menggunakanCGSizeZero
sebagai penjaga tidak membantu Anda membedakan antara nilai yang tidak disetel dan disetel ke nol. Selain itu, ini berlaku sama baiknya untuk jenis lain yang dimuat dari nib (atau di mana pun setelahnyainit
): string, referensi untuk subview, dll.let foo? = 42
, bukanlet foo! = 42
). Ini tidak membahas itu. (Ini mungkin jawaban yang relevan tentang opsional, ingatlah, tetapi bukan tentang opsional yang terbuka secara implisit yang merupakan hewan yang berbeda / terkait.)Apple memberikan contoh yang bagus dalam Bahasa Pemrograman Swift -> Penghitungan Referensi Otomatis -> Menyelesaikan Siklus Referensi yang Kuat Antara Instance Kelas -> Referensi Tidak Dimiliki dan Properti Opsional yang Tidak Dibungkus Secara Tersirat
sumber
Dasar pemikiran dari pilihan implisit lebih mudah untuk dijelaskan dengan terlebih dahulu melihat alasan untuk membuka paksa.
Membuka paksa paksa opsional (implisit atau tidak), menggunakan! operator, berarti Anda yakin bahwa kode Anda tidak memiliki bug dan opsional sudah memiliki nilai di mana itu sedang dibuka. Tanpa ! operator, Anda mungkin hanya akan menegaskan dengan penjilidan opsional:
yang tidak sebaik
Sekarang, opsional implisit memungkinkan Anda menyatakan memiliki opsional yang Anda harapkan akan selalu memiliki nilai ketika dibuka, dalam semua kemungkinan aliran. Jadi itu hanya selangkah lebih maju dalam membantu Anda - dengan melonggarkan persyaratan penulisan! untuk membuka setiap kali, dan memastikan bahwa runtime masih akan kesalahan jika asumsi Anda tentang aliran salah.
sumber
init
(yang mungkin bahkan tidak Anda terapkan), tetapi mereka ' kembali dijamin akan ditetapkan setelahawakeFromNib
/viewDidLoad
.Jika Anda tahu pasti, nilai kembali dari opsional, bukan
nil
, Secara opsional Unwrapped Optional digunakan untuk secara langsung menangkap nilai-nilai dari opsional dan non opsional tidak bisa.Jadi ini adalah perbedaan antara penggunaan
let someString : String!
danlet someString : String
sumber
Saya pikir
Optional
itu nama yang buruk untuk konstruksi ini yang membingungkan banyak pemula.Bahasa lain (Kotlin dan C # misalnya) menggunakan istilah ini
Nullable
, dan itu membuatnya jauh lebih mudah untuk memahami ini.Nullable
berarti Anda dapat menetapkan nilai nol ke variabel jenis ini. Jadi jika ituNullable<SomeClassType>
, Anda dapat menetapkan nol untuk itu, jika itu hanyaSomeClassType
, Anda tidak bisa. Itulah cara kerja Swift.Mengapa menggunakannya? Nah, kadang-kadang Anda harus memiliki nol, itu sebabnya. Misalnya, ketika Anda tahu bahwa Anda ingin memiliki bidang dalam suatu kelas, tetapi Anda tidak dapat menetapkannya untuk apa pun ketika Anda membuat turunan dari kelas itu, tetapi Anda nanti akan melakukannya. Saya tidak akan memberikan contoh, karena orang-orang sudah menyediakannya di sini. Saya hanya menulis ini untuk memberikan 2 sen saya.
Btw, saya sarankan Anda melihat bagaimana ini bekerja dalam bahasa lain, seperti Kotlin dan C #.
Inilah tautan yang menjelaskan fitur ini di Kotlin: https://kotlinlang.org/docs/reference/null-safety.html
Bahasa lain, seperti Java dan Scala memiliki
Optional
s, tetapi mereka bekerja secara berbeda dariOptional
s di Swift, karena tipe Java dan Scala semuanya dapat dibatalkan secara default.Semua dalam semua, saya pikir fitur ini seharusnya dinamai
Nullable
dalam Swift, dan tidakOptional
...sumber
Implicitly Unwrapped Optional
adalah gula sintaksis untukOptional
itu tidak memaksa programmer untuk membuka bungkus variabel. Ini dapat digunakan untuk variabel yang tidak dapat diinisialisasi selamatwo-phase initialization process
dan menyiratkan non-nil. Variabel ini berperilaku sebagai non-nil tetapi sebenarnya adalah variabel opsional . Contoh yang bagus adalah - outlet Interface BuilderOptional
biasanya lebih disukaisumber