题 Swift属性覆盖不起作用


当我尝试覆盖属性时,我收到错误“无法覆盖具有只读属性的可变属性”

我已经在超类中提供了get和set。

class Card {
    var contents:String {
        get {
            return self.contents
        }
        set {
            self.contents = newValue
        }
    }
    init() {
        self.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
        }
    }
}

我究竟做错了什么?


16
2017-09-30 03:21


起源




答案:


如果您要覆盖的属性同时具有getter和setter,则还需要在子类中同时提供这两个属性。这是 Swift语言指南的相关部分 (强调我的):

您可以将继承的只读属性显示为读写   通过在子类中提供getter和setter来实现属性   属性覆盖。 但是,你不能提出遗传   读写属性作为只读属性。

如果您没有对该值执行任何特殊操作,那么您通常希望将设置的值传递给基类:

set {
    super.contents = newValue
}

你也可以用一个空的setter来丢弃这个值(虽然我想不出有理由这么做):

set { }

我还想指出你有一个无限循环 contents 在你的财产 Card 类。当你这样做:

get {
    return self.contents
}

你实际上只是再次调用相同的getter,创建一个无限循环;你对二传手做同样的事情。 Swift不像Objective-C那样自动为您的属性创建ivars,因此您需要自己创建它们。创建该属性的更合适的方法是执行以下操作:

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

但是,因为除了设置和返回之外你没有做任何其他事情 _contents 在你的setter和getter中,你可以简化它:

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

    }
}

注意:  contents 也可能是使用可选项的好选择(String?)并将其设置为 nil 而不是将其初始化为空字符串。


23
2017-09-30 03:38





编译器错误消息非常简单: Cardcontents 财产是 易变的,也就是说它有一个 set 方法除了 get 方法。

您的覆盖只会添加一个 get 方法,你需要添加一个 set 方法也是。

我想这就是你想要的:

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

3
2017-09-30 03:32



newValue 是默认的,对吗?所以你可以使用 set {, 我认为 - Dan Rosenstark