Karena Swift mendukung metode dan initializer overloading, Anda dapat menempatkan beberapa di init
samping satu sama lain dan menggunakan mana pun yang Anda anggap nyaman:
class Person {
var name:String
init(name: String) {
self.name = name
}
init() {
self.name = "John"
}
}
Jadi mengapa convenience
kata kunci bahkan ada? Apa yang membuat yang berikut ini jauh lebih baik?
class Person {
var name:String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "John")
}
}
swift
initialization
Desmond Hume
sumber
sumber
Jawaban:
Jawaban yang ada hanya menceritakan setengah dari
convenience
cerita. Separuh cerita yang lain, separuh dari tidak ada jawaban yang ada, menjawab pertanyaan yang telah diposting Desmond dalam komentar:Saya menyentuhnya sedikit dalam jawaban ini , di mana saya membahas beberapa aturan inisialisasi Swift secara detail, tetapi fokus utama ada pada
required
kata tersebut. Tetapi jawaban itu masih menyinggung sesuatu yang relevan dengan pertanyaan ini dan jawaban ini. Kita harus memahami cara kerja pewarisan initializer Swift.Karena Swift tidak memungkinkan untuk variabel yang tidak diinisialisasi, Anda tidak dijamin akan mewarisi semua (atau apa pun) inisialisasi dari kelas yang Anda warisi. Jika kami subkelas dan menambahkan variabel instance yang tidak diinisialisasi ke dalam subkelas kami, kami telah berhenti mewarisi inisialisasi. Dan sampai kita menambahkan inisialisasi kita sendiri, kompiler akan meneriaki kita.
Agar lebih jelas, variabel instance yang tidak diinisialisasi adalah variabel instance apa saja yang tidak diberi nilai default (dengan mengingat bahwa opsional dan opsional yang tidak terbuka secara otomatis mengasumsikan nilai default
nil
).Jadi dalam hal ini:
a
adalah variabel instance tidak diinisialisasi. Ini tidak akan dikompilasi kecuali kami memberikana
nilai default:atau inisialisasi
a
dalam metode penginisialisasi:Sekarang, mari kita lihat apa yang terjadi jika kita subkelas
Foo
, ya?Baik? Kami menambahkan variabel, dan kami menambahkan penginisialisasi untuk menetapkan nilai
b
sehingga akan dikompilasi. Bergantung pada bahasa apa Anda berasal, Anda mungkin berharap bahwa inisialisasiBar
bawaanFoo
,,init(a: Int)
. Tapi ternyata tidak. Dan bagaimana mungkin? BagaimanaFoo
'sinit(a: Int)
know bagaimana menetapkan nilai keb
variabel yangBar
ditambahkan? Tidak. Jadi kita tidak dapat menginisialisasi aBar
instance dengan penginisialisasi yang tidak dapat menginisialisasi semua nilai kami.Apa hubungannya semua ini dengan
convenience
?Baiklah, mari kita lihat aturan tentang pewarisan initializer :
Perhatikan Aturan 2, yang menyebutkan inisialisasi kenyamanan.
Jadi apa yang
convenience
kata kunci yang lakukan yaitu menunjukkan kepada kita yang initializers dapat diwariskan oleh subclass bahwa variabel add misalnya tanpa nilai default.Mari kita ambil contoh
Base
kelas ini:Perhatikan kita memiliki tiga
convenience
inisialisasi di sini. Itu berarti kami memiliki tiga inisialisasi yang dapat diwariskan. Dan kami memiliki satu penginisialisasi yang ditunjuk (penginisialisasi yang ditunjuk hanyalah penginisialisasi yang bukan penginisialisasi kenyamanan).Kami dapat membuat instance instance dari kelas dasar dalam empat cara berbeda:
Jadi, mari kita membuat subkelas.
Kami mewarisi dari
Base
. Kami menambahkan variabel instan kami sendiri dan kami tidak memberikan nilai default, jadi kami harus menambahkan inisialisasi kami sendiri. Kami menambahkan satu,init(a: Int, b: Int, c: Int)
tapi itu tidak cocok dengan tanda tangan dariBase
kelas yang ditunjuk initializer:init(a: Int, b: Int)
. Itu berarti, kita tidak mewarisi apapun initializers dariBase
:Jadi, apa yang akan terjadi jika kami mewarisi dari
Base
, tetapi kami melanjutkan dan menerapkan penginisialisasi yang cocok dengan penginisialisasi yang ditunjuk dariBase
?Sekarang, selain dua inisialisasi yang kami terapkan langsung di kelas ini, karena kami menerapkan inisialisasi
Base
kelas pencocokan yang ditunjuk oleh initializer, kami harus mewarisi semua inisialisasiBase
kelasconvenience
:Fakta bahwa penginisialisasi dengan tanda tangan yang cocok ditandai sebagai
convenience
tidak membuat perbedaan di sini. Ini hanya berarti bahwaInheritor
hanya memiliki satu inisialisasi yang ditunjuk. Jadi jika kita mewarisi dariInheritor
, kita hanya perlu menerapkan satu penginisialisasi yang ditunjuk, dan kemudian kita akan mewarisiInheritor
penginisialisasi kenyamanan, yang pada gilirannya berarti kita telah menerapkan semuaBase
inisialisasi yang ditunjuk dan dapat mewarisiconvenience
inisialisasi.sumber
init(a: Int)
akan meninggalkanb
diinisialisasi.Sebagian besar kejelasan. Dari Anda contoh kedua,
diperlukan atau ditunjuk . Itu harus menginisialisasi semua konstanta dan variabel Anda. Inisialisasi kenyamanan adalah opsional, dan biasanya dapat digunakan untuk mempermudah inisialisasi. Misalnya, katakanlah kelas Person Anda memiliki jenis kelamin variabel opsional:
dimana Gender adalah enum
Anda bisa mendapatkan inisialisasi yang mudah seperti ini
Inisialisasi kenyamanan harus memanggil inisialisasi yang ditunjuk atau diminta di dalamnya. Jika kelas Anda adalah subclass, ia harus memanggil
super.init()
inisialisasi itu.sumber
convenience
kata kunci tetapi Swift masih akan mengganggunya. Itu bukan jenis kesederhanaan yang saya harapkan dari Apple =)Nah, hal pertama yang terlintas dalam pikiran saya adalah bahwa ini digunakan dalam pewarisan kelas untuk organisasi kode dan keterbacaan. Melanjutkan
Person
kelas Anda , pikirkan skenario seperti iniDengan initializer kenyamanan saya dapat membuat
Employee()
objek tanpa nilai, karenanya kataconvenience
sumber
convenience
kata kunci diambil, bukankah Swift mendapatkan informasi yang cukup untuk berperilaku dengan cara yang persis sama?convenience
kata kunci, Anda tidak dapat menginisialisasiEmployee
objek tanpa argumen.Employee()
panggilanconvenience
penginisialisasi (yang diwarisi, karena )init()
, yang memanggilself.init(name: "Unknown")
.init(name: String)
, juga penginisialisasi kenyamanan untukEmployee
, memanggil penginisialisasi yang ditunjuk.Terlepas dari poin yang dijelaskan pengguna lain di sini adalah sedikit pemahaman saya.
Saya sangat merasakan hubungan antara penginisialisasi kenyamanan dan ekstensi. Bagi saya inisialisasi kenyamanan paling berguna ketika saya ingin memodifikasi (dalam banyak kasus membuatnya pendek atau mudah) inisialisasi kelas yang ada.
Misalnya beberapa kelas pihak ketiga yang Anda gunakan memiliki
init
dengan empat parameter tetapi dalam aplikasi Anda dua yang terakhir memiliki nilai yang sama. Untuk menghindari lebih banyak mengetik dan membuat kode Anda bersih, Anda bisa mendefinisikanconvenience init
dengan hanya dua parameter dan di dalamnya memanggilself.init
dengan terakhir ke parameter dengan nilai default.sumber
convenience
di depan inisialisasi saya hanya karena saya perlu meneleponself.init
dari itu? Ini sepertinya berlebihan dan agak tidak nyaman.Menurut dokumentasi Swift 2.1 ,
convenience
inisialisasi harus mematuhi beberapa aturan khusus:Sebuah
convenience
initializer hanya dapat memanggil intializers di kelas yang sama, tidak di kelas super (hanya di seberang, tidak sampai)Sebuah
convenience
initializer harus memanggil ditunjuk initializer di suatu tempat dalam rantaiSebuah
convenience
initializer tidak dapat mengubah APAPUN properti sebelum itu telah disebut initializer lain - sedangkan initializer yang ditunjuk harus menginisialisasi properti yang diperkenalkan oleh kelas saat sebelum memanggil initializer lain.Dengan menggunakan
convenience
kata kunci, kompiler Swift tahu bahwa ia harus memeriksa kondisi ini - jika tidak maka tidak akan bisa.sumber
convenience
kata kunci.let
properti). Itu tidak dapat menginisialisasi properti. Inisialisasi yang ditunjuk memiliki tanggung jawab untuk menginisialisasi semua properti yang diperkenalkan sebelum memanggil kesuper
inisialisasi yang ditunjuk.Kelas dapat memiliki lebih dari satu penginisialisasi yang ditunjuk. Penginisialisasi kenyamanan adalah penginisialisasi sekunder yang harus memanggil inisialisasi yang ditunjuk dari kelas yang sama.
sumber