web-dev-qa-db-ja.com

Swiftプロパティのオーバーライドが機能しない

プロパティをオーバーライドしようとすると、「読み取り専用プロパティで変更可能なプロパティをオーバーライドできません」というエラーが表示されます

スーパークラスでgetおよびsetを提供しました。

class Card {
    var contents:String {
        get {
            return self.contents
        }
        set {
            self.contents = newValue
        }
    }
    init() {
        self.contents = ""
    }
}

これが「contents」プロパティをオーバーライドしようとしている私のサブクラスです。

class PlayingCard: Card {
    override var contents:String { //<-- this is where I get the build error
        get {
            var rankStrings:Array<String> = PlayingCard.rankStrings()
            return rankStrings[Int(self.rank)] + self.suit
        }
    }
}

正確に私は何を間違っていますか?

21
DerrickHo328

オーバーライドするプロパティにゲッターとセッターの両方がある場合は、サブクラスにも両方を提供する必要があります。これが Swift言語ガイド)の関連部分 (私の強調)です:

サブクラスプロパティのオーバーライドでゲッターとセッターの両方を提供することにより、継承された読み取り専用プロパティを読み取り/書き込みプロパティとして提示できます。 ただし、継承された読み取り/書き込みプロパティを読み取り専用プロパティとして提示することはできません。

値で特別なことを何もしていない場合は、通常、設定されている値を基本クラスに渡します。

set {
    super.contents = newValue
}

空のセッターを使用して値を破棄することもできます(これをオフハンドで行う正当な理由は考えられませんが)。

set { }

また、contentsクラスのCardプロパティに無限ループがあることも指摘しておきます。あなたがこれをするとき:

get {
    return self.contents
}

実際には、同じゲッターを再度呼び出して無限ループを作成しています。セッターでも同じことをしています。 Swiftは、Objective-Cが行ったようにプロパティのivarを自動的に作成しないため、自分で作成する必要があります。そのプロパティを作成するより適切な方法は、次のようなものです。

class Card {
    private var _contents: String
    var contents: String {
        get {
            return _contents
        }
        set {
            _contents = newValue
        }
    }
    init() {
        _contents = ""
    }
}

ただし、セッターとゲッターで_contentsを設定して返すこと以外は何もしていないので、次のように簡略化できます。

class Card {
    var contents: String = ""
    init() {

    }
}

注:contentsは、オプションの(String?)の使用にも適している可能性があります空の文字列に初期化するのではなく、nilに設定します。

31
Mike S

コンパイラエラーメッセージはかなり単純です。Cardcontentsプロパティはmutableです。つまり、setメソッドに加えてgetメソッドがあります。

オーバーライドはgetメソッドのみを追加します。setメソッドも追加する必要があります。

私はこれがあなたが望むものだと思います:

set(newValue) {
    rankStrings[Int(self.rank)] = newValue;
}
4
Dai