Mevcut cevaplar conveniencehikayenin sadece yarısını anlatıyor. Hikayenin diğer yarısı, mevcut cevapların hiçbirinin kapsamadığı yarısı, Desmond'un yorumlarda yayınladığı soruyu yanıtlıyor:
Swift, neden conveniencesadece ondan aramam gerektiği için beni başlatıcımın önüne koymaya zorlasın self.init? ''
Swift'in başlatıcı kurallarından birkaçını ayrıntılı olarak ele aldığım bu cevapta biraz değindim, ancak asıl odak noktası kelime üzerindeydi. Ancak bu cevap hala bu soru ve bu cevapla ilgili bir şeye hitap ediyordu. Swift başlatıcı mirasının nasıl çalıştığını anlamalıyız.required
Swift başlatılmamış değişkenlere izin vermediğinden, miras aldığınız sınıftan tüm başlatıcıları (veya herhangi birini) devralmanız garanti edilmez. Alt sınıfa ayrılır ve ilklendirilmemiş örnek değişkenlerini alt sınıfımıza eklersek, başlatıcıları devralmayı durdurmuş oluruz. Ve biz kendi başlatıcılarımızı ekleyene kadar, derleyici bize bağıracak.
Açık olmak gerekirse, başlatılmamış bir örnek değişkeni, varsayılan bir değer verilmeyen herhangi bir örnek değişkendir (isteğe bağlı ve örtük olarak kapatılmamış seçeneklerin otomatik olarak varsayılan bir değer aldığını unutmayın nil).
Yani bu durumda:
class Foo {
var a: Int
}
abaşlatılmamış bir örnek değişkendir. aVarsayılan bir değer vermedikçe bu derlenmeyecektir :
class Foo {
var a: Int = 0
}
veya abir başlatıcı yönteminde başlat:
class Foo {
var a: Int
init(a: Int) {
self.a = a
}
}
Şimdi, alt sınıfa ayrılırsak ne olacağını görelim, olur Foomu?
class Bar: Foo {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
Sağ? Bir değişken ekledik ve bderlenebilmesi için bir değer ayarlamak üzere bir başlatıcı ekledik . Hangi dilden geldiğinize bağlı olarak, bunun 'ın başlatıcısını Bardevralmasını bekleyebilirsiniz . Ama öyle değil. Ve nasıl olabilir? Nasıl yok 'ın biliyorum nasıl bir değer atamak için bu değişkenin ekledi? Öyle değil. Dolayısıyla, tüm değerlerimizi başlatamayan bir başlatıcıyla bir örneği başlatamayız.Fooinit(a: Int)Fooinit(a: Int)bBarBar
Bunların ne alakası var convenience?
Peki, başlatıcı mirasıyla ilgili kurallara bakalım :
Kural 1
Alt sınıfınız herhangi bir atanmış başlatıcı tanımlamıyorsa, otomatik olarak tüm üst sınıf atanmış başlatıcılarını devralır.
Kural 2
Alt sınıfınız, birinci sınıf atanmış başlatıcılarının tümünün bir uygulamasını sağlıyorsa - bunları kural 1'e göre miras alarak veya tanımının bir parçası olarak özel bir uygulama sağlayarak - o zaman tüm üst sınıf uygunluk başlatıcılarını otomatik olarak devralır.
Kolaylık başlatıcılardan bahseden Kural 2'ye dikkat edin.
Yani convenienceanahtar kelimenin yaptığı şey, bize hangi başlatıcıların varsayılan değerler olmadan örnek değişkenleri ekleyen alt sınıflar tarafından miras alınabileceğini belirtmektir .
Bu örnek Basedersi ele alalım :
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)
}
}
convenienceBurada üç başlatıcımızın olduğuna dikkat edin . Bu, miras alınabilen üç başlatıcımız olduğu anlamına gelir. Ve bir atanmış başlatıcımız var (atanmış bir başlatıcı, basitçe bir kolaylık başlatıcı olmayan herhangi bir başlatıcıdır).
Temel sınıfın örneklerini dört farklı şekilde başlatabiliriz:

Öyleyse bir alt sınıf oluşturalım.
class NonInheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
}
Miras alıyoruz Base. Kendi örnek değişkenimizi ekledik ve buna varsayılan bir değer vermedik, bu yüzden kendi başlatıcılarımızı eklemeliyiz. Biz bir ilave, init(a: Int, b: Int, c: Int)ama imzası eşleşmiyor Basesınıfın başlatıcısı atanmış bir: init(a: Int, b: Int). Bu, aşağıdakilerden herhangi bir başlatıcı miras almadığımız anlamına gelir Base:

Öyleyse, miras alsaydık ne olurdu Base, ama devam ettik ve atanan başlatıcıyla eşleşen bir başlatıcı uyguladık 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)
}
}
Şimdi, doğrudan bu sınıfta uyguladığımız iki başlatıcıya ek olarak, Basesınıfın atanmış başlatıcısıyla eşleşen bir başlatıcı uyguladığımız için , Basesınıfın tüm conveniencebaşlatıcılarını devralabiliriz :

Eşleşen imzaya sahip başlatıcının olarak işaretlenmiş convenienceolması burada hiçbir fark yaratmaz. Bu Inheritor, yalnızca bir belirlenmiş başlatıcıya sahip olduğu anlamına gelir . Öyleyse miras alırsak Inheritor, o atanmış başlatıcıyı uygulamamız gerekir ve sonra Inheritorkolaylık başlatıcısını devralırız , bu da tüm Baseatanmış başlatıcıları uyguladığımız ve onun conveniencebaşlatıcılarını devralabileceğimiz anlamına gelir .