Mevcut cevaplar convenience
hikayenin 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 convenience
sadece 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
}
a
başlatılmamış bir örnek değişkendir. a
Varsayılan bir değer vermedikçe bu derlenmeyecektir :
class Foo {
var a: Int = 0
}
veya a
bir 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 Foo
mu?
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 b
derlenebilmesi 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ı Bar
devralması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.Foo
init(a: Int)
Foo
init(a: Int)
b
Bar
Bar
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 convenience
anahtar 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 Base
dersi 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)
}
}
convenience
Burada üç 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 Base
sı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, Base
sınıfın atanmış başlatıcısıyla eşleşen bir başlatıcı uyguladığımız için , Base
sınıfın tüm convenience
başlatıcılarını devralabiliriz :
Eşleşen imzaya sahip başlatıcının olarak işaretlenmiş convenience
olması 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 Inheritor
kolaylık başlatıcısını devralırız , bu da tüm Base
atanmış başlatıcıları uyguladığımız ve onun convenience
başlatıcılarını devralabileceğimiz anlamına gelir .