Swift'de saklanan bir mülkü geçersiz kılma


126

Derleyicinin saklanan bir özelliği başka bir depolanmış değerle geçersiz kılmama izin vermediğini fark ettim (garip görünüyor):

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

Ancak, bunu hesaplanmış bir mülkle yapmama izin verilir:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}

Neden ona başka bir değer vermeme izin verilmiyor?

Depolanan bir mülkü geçersiz kılmak neden iğrençtir ve bunu hesaplanmış bir koşer ile yapmaktır? Nerede düşünüyorlar?


Yanıtlar:


82

Neden ona başka bir değer vermeme izin verilmiyor?

Devralınan bir mülke farklı bir değer vermenize kesinlikle izin verilir. Bu ilk değeri alan bir yapıcıda özelliği başlatırsanız ve türetilmiş sınıftan farklı bir değer iletirseniz bunu yapabilirsiniz:

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)

Bir özelliği geçersiz kılmak, ona yeni bir değer vermekle aynı şey değildir - daha çok bir sınıfa farklı bir özellik vermek gibidir. Aslında, hesaplanan bir özelliği geçersiz kıldığınızda olan şey budur: temel sınıftaki özelliği hesaplayan kod, türetilmiş sınıftaki o özellik için geçersiz kılmayı hesaplayan kodla değiştirilir .

Gerçek depolanmış özelliği geçersiz kılmak, yani lightSaberColorbaşka bir davranışa sahip midir?

Gözlemciler dışında, depolanan özelliklerin davranışı yoktur, bu nedenle geçersiz kılacak hiçbir şey yoktur. Mülke farklı bir değer vermek, yukarıda açıklanan mekanizma ile mümkündür. Bu, sorudaki örneğin farklı bir sözdizimi ile elde etmeye çalıştığı şeyi tam olarak yapar.


2
@MaxMacLeod Gözlemciler dışında, depolanan özelliklerin davranışı yoktur, dolayısıyla geçersiz kılacak hiçbir şey yoktur. Depolanan bir mülke alt sınıfta farklı bir değer vermek istiyordu, ancak bunu başarma mekanizmasından emin değildi. Cevap, Swift'de nasıl yapılabileceğini açıklıyor. Geç cevap verdiğim için özür dilerim, yorumunuz olumsuz oyları çekecek kadar kafa karışıklığına neden oluyor gibi görünüyor, bu yüzden neler olduğunu açıklamaya karar verdim.
dasblinkenlight

55

Benim için örneğiniz Swift 3.0.1'de çalışmıyor.

Oyun alanına bu kodu girdim:

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}

Xcode'da derleme zamanında hata verir:

değişmez 'let' özelliği 'lightsaberColor' değerini bir 'var' alıcısıyla geçersiz kılamaz

Hayır, saklanan özelliğin türünü değiştiremezsiniz. Liskov İkame İlkesi sizi, bir alt sınıfın üst sınıfın istendiği bir yerde kullanılmasına izin vermeye zorlar .

Ancak, olarak değiştirirseniz varve dolayısıyla sethesaplanan özelliğe eklerseniz , depolanan özelliği aynı türden hesaplanmış bir özellik ile geçersiz kılabilirsiniz.

class Jedi {
    var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
        set {
            // nothing, because only red is allowed
        }
    }
}

Bu mümkündür çünkü depolanmış özellikten hesaplanmış özelliğe geçiş yapmak mantıklı olabilir.

Ancak depolanmış bir varözelliği, depolanan birvar kılınması mantıklı değildir çünkü yalnızca özelliğin değerini değiştirebilirsiniz.

Ancak, depolanmış bir özelliği depolanan bir mülkle geçersiz kılamazsınız.


Sith'in Jedi olduğunu söylemem: -P. Bu nedenle bunun işe yaramayacağı açıktır.


18
class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}

13
Bu kod parçacığı soruyu çözebilirken, bir açıklama eklemek, yayınınızın kalitesini iyileştirmeye gerçekten yardımcı olur. Gelecekte okuyucular için soruyu yanıtladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceklerini unutmayın.
DimaSan

15

Muhtemelen mülk için başka bir değer atamak istiyorsunuz:

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}

9
aynısı yukarıdaki yorum başına geçerlidir
Max MacLeod

10

Swift 4 için, Apple'ın belgelerinden :

Bu özellik için kendi özel alıcı ve ayarlayıcınızı sağlamak için veya altta yatan özellik değeri değiştiğinde geçersiz kılma özelliğinin gözlemlenmesini sağlamak için özellik gözlemcileri eklemek için miras alınan bir örneği veya tür özelliğini geçersiz kılabilirsiniz.


7

Swift'de bunu yapmak maalesef mümkün değil. En iyi alternatif şudur:

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}

3

Bir görünüm denetleyicisi için bir sabit ayarlamak için aynı problemi yaşadım.

Görünümü yönetmek için arabirim oluşturucuyu kullandığım için kullanamıyorum init(), bu nedenle çözümüm diğer yanıtlara benziyordu, ancak hem temel hem de miras alınan sınıflarda salt okunur bir hesaplanan değişken kullanmıştım.

class Jedi {
    var type: String {
        get { return "Blue" }
    }
}

class Sith: Jedi {
    override var type: String {
        get { return "Red" }
    }
}

3

Swift 5'te bunu yapmaya çalışırsanız, bir

Değişmez 'let' özelliği 'lightSaberColor' bir 'var' alıcısıyla geçersiz kılınamaz

En iyi bahsiniz, onu hesaplanmış bir mülk olarak ilan etmektir.

Bu, get {}işlevi geçersiz kıldığımız için çalışır.

class Base {
   var lightSaberColor: String { "base" }
}

class Red: Base {
   override var lightSaberColor: String { "red" }
}

2

Swift bir değişkeni geçersiz kılmana izin vermiyor stored propertyBunun yerine kullanabilirsincomputed property

class A {
    var property1 = "A: Stored Property 1"

    var property2: String {
        get {
            return "A: Computed Property 2"
        }
    }

    let property3 = "A: Constant Stored Property 3"

    //let can not be a computed property
    
    func foo() -> String {
        return "A: foo()"
    }
}

class B: A {

    //now it is a computed property
    override var property1: String {

        set { }
        get {
            return "B: overrode Stored Property 1"
        }
    }

    override var property2: String {
        get {
            return "B: overrode Computed Property 2"
        }
    }
    
    override func foo() -> String {
        return "B: foo()"
    }

    //let can not be overrode
}
func testPoly() {
    let a = A()
    
    XCTAssertEqual("A: Stored Property 1", a.property1)
    XCTAssertEqual("A: Computed Property 2", a.property2)
    
    XCTAssertEqual("A: foo()", a.foo())
    
    let b = B()
    XCTAssertEqual("B: overrode Stored Property 1", b.property1)
    XCTAssertEqual("B: overrode Computed Property 2", b.property2)
    
    XCTAssertEqual("B: foo()", b.foo())
    
    //B cast to A
    XCTAssertEqual("B: overrode Stored Property 1", (b as! A).property1)
    XCTAssertEqual("B: overrode Computed Property 2", (b as! A).property2)
    
    XCTAssertEqual("B: foo()", (b as! A).foo())
}

Bir sınıf alanının geçersiz kılınamadığı ve derleme zamanında tanımlandığı için polimorfizmi desteklemediği Java ile karşılaştırıldığında daha açıktır. Buna değişken gizleme denir [Hakkında] Okuması / desteklemesi zor olduğu için bu tekniğin kullanılması tavsiye edilmez

[Swift özelliği]


1

Ayrıca, geçersiz kılmak için bir işlev de kullanabilirsiniz. Doğrudan cevap değil, ancak bu konuyu zenginleştirebilir)

A sınıfı

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}

Sınıf B: A

public func shouldDoSmth() -> Bool {
    return false
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.