web-dev-qa-db-ja.com

Swiftの保存されたプロパティのオーバーライド

コンパイラは、保存されたプロパティを別の保存された値で上書きさせないことに気付きました(奇妙に思えます):

class Jedi {
    var lightSaberColor = "Blue"
}


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

ただし、計算されたプロパティを使用してこれを行うことができます:

class Jedi {
    let lightSaberColor = "Blue"
}


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

}

別の値を与えることが許可されないのはなぜですか?

なぜ保存されたプロパティでオーバーライドするのが憎悪であり、計算されたコーシャでそれを行うのですか?彼らは何を考えているの?

102
cfischer

なぜ別の値を与えることが許可されないのですか?

継承されたプロパティに異なる値を与えることは間違いなく許可されています。その初期値を取得するコンストラクターでプロパティを初期化し、派生クラスから異なる値を渡す場合、それを行うことができます。

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)

プロパティをオーバーライドすることは、新しい値を与えることと同じではなく、クラスに異なるプロパティを与えることに似ています。実際、計算されたプロパティをオーバーライドすると、それが起こります。基本クラスのプロパティを計算するコードは、派生クラスのそのプロパティのオーバーライドを計算するコードによってreplacedです。

実際に保存されているプロパティ、つまりlightSaberColorをオーバーライドすることは可能ですか?

オブザーバーを除き、保存されたプロパティには動作がないため、実際にオーバーライドするものはありません。上記のメカニズムにより、プロパティに異なる値を与えることができます。これは、異なる構文を使用して、質問の例が達成しようとしていることとまったく同じです。

59
dasblinkenlight

私の場合、あなたの例はSwift 3.0.1では動作しません。

このコードを遊び場に入力しました:

class Jedi {
    let lightsaberColor = "Blue"
}

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

Xcodeでコンパイル時にエラーをスローします。

不変の「let」プロパティ「lightsaberColor」を「var」のゲッターでオーバーライドできません

いいえ、保存されたプロパティのタイプを変更することはできません。 Liskov Substitution Principle forcesスーパークラスが必要な場所でサブクラスを使用できるようにします。

しかし、それをvarに変更し、したがって、計算プロパティにsetを追加すると、同じタイプの計算プロパティで保存プロパティをオーバーライドできます。

class Jedi {
    var lightsaberColor = "Blue"
}


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

保存されたプロパティから計算されたプロパティに切り替えるのが理にかなっているので、これは可能です。

ただし、保存されたvarプロパティを保存されたvarプロパティでオーバーライドすることは意味がありません。これは、プロパティの値のみを変更できるためです。

ただし、ストアドプロパティをストアドプロパティでオーバーライドすることはできません。


シスがジェダイだとは言いません:-P。したがって、これが機能しないことは明らかです。

42
Binarian

おそらく、プロパティに別の値を割り当てる必要があります。

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}
13
zisoft
class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}
12
Zhiping Yang

Swift 4の場合、 Appleのドキュメント から:

継承されたインスタンスまたは型プロパティをオーバーライドして、そのプロパティに独自のカスタムgetterおよびsetterを提供したり、プロパティオブザーバを追加して、基になるプロパティ値が変更されたときにオーバーライドプロパティが監視できるようにすることができます。

9
riyasavla

Swiftでは、残念ながらこれを行うことはできません。最適な代替手段は次のとおりです。

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


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

ビューコントローラーに定数を設定するのと同じ問題がありました。

インターフェイスビルダーを使用してビューを管理しているため、init()を使用できないため、基本クラスと継承クラスの両方で読み取り専用の計算変数を使用することを除いて、回避策は他の回答と同様でした。

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

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

関数を使用してオーバーライドすることもできます。直接的な答えではありませんが、このトピックを充実させることができます)

クラスA

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

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

クラスB:A

public func shouldDoSmth() -> Bool {
    return false
}
0
Nik Kov