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:
Mengapa Swift memaksa saya untuk meletakkan convenience
di depan inisialisasi saya hanya karena saya perlu menelepon self.init
dari itu? `
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:
class Foo {
var a: Int
}
a
adalah variabel instance tidak diinisialisasi. Ini tidak akan dikompilasi kecuali kami memberikan a
nilai default:
class Foo {
var a: Int = 0
}
atau inisialisasi a
dalam metode penginisialisasi:
class Foo {
var a: Int
init(a: Int) {
self.a = a
}
}
Sekarang, mari kita lihat apa yang terjadi jika kita subkelas Foo
, ya?
class Bar: Foo {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
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 inisialisasi Bar
bawaan Foo
,, init(a: Int)
. Tapi ternyata tidak. Dan bagaimana mungkin? Bagaimana Foo
's init(a: Int)
know bagaimana menetapkan nilai ke b
variabel yang Bar
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 :
Aturan 1
Jika subkelas Anda tidak menentukan inisialisasi yang ditunjuk, subisialisasi Anda secara otomatis akan mewarisi semua inisialisasi yang ditentukan oleh superclass.
Aturan 2
Jika subclass Anda memberikan implementasi dari semua inisialisasi yang ditentukan oleh superclass-baik dengan mewarisinya sesuai aturan 1, atau dengan memberikan implementasi kustom sebagai bagian dari definisi-maka secara otomatis mewarisi semua inisialisasi kenyamanan superclass.
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:
class Base {
let a: Int
let b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
convenience init() {
self.init(a: 0, b: 0)
}
convenience init(a: Int) {
self.init(a: a, b: 0)
}
convenience init(b: Int) {
self.init(a: 0, b: b)
}
}
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.
class NonInheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
}
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 dari Base
kelas yang ditunjuk initializer: init(a: Int, b: Int)
. Itu berarti, kita tidak mewarisi apapun initializers dari Base
:
Jadi, apa yang akan terjadi jika kami mewarisi dari Base
, tetapi kami melanjutkan dan menerapkan penginisialisasi yang cocok dengan penginisialisasi yang ditunjuk dari Base
?
class Inheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
convenience override init(a: Int, b: Int) {
self.init(a: a, b: b, c: 0)
}
}
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 inisialisasi Base
kelas convenience
:
Fakta bahwa penginisialisasi dengan tanda tangan yang cocok ditandai sebagai convenience
tidak membuat perbedaan di sini. Ini hanya berarti bahwa Inheritor
hanya memiliki satu inisialisasi yang ditunjuk. Jadi jika kita mewarisi dari Inheritor
, kita hanya perlu menerapkan satu penginisialisasi yang ditunjuk, dan kemudian kita akan mewarisi Inheritor
penginisialisasi kenyamanan, yang pada gilirannya berarti kita telah menerapkan semua Base
inisialisasi yang ditunjuk dan dapat mewarisi convenience
inisialisasi.