Swift property override not working

ios8overridingpropertiesswift

When I try to override a property I get an error "can not override mutable property with read-only property"

I have provided get and set in the super class.

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

Here is my Subclass where I am trying to override the "contents" property.

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
        }
    }
}

What exactly am I doing wrong?

Best Answer

If the property you're overriding has both a getter and a setter, you need to provide both in your subclass as well. Here's the relevant part from the Swift language guide (emphasis mine):

You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property.

If you're not doing anything special with the value, then you'll typically want to pass the value being set on to the base class:

set {
    super.contents = newValue
}

You could also just discard the value with an empty setter (although I can't think of a good reason to do this offhand):

set { }

I also wanted to point out that you have an infinite loop in the contents property in your Card class. When you you do this:

get {
    return self.contents
}

You're actually just calling that same getter again, creating an infinite loop; you're doing the same with the setter. Swift doesn't create ivars for your properties automatically like Objective-C did, so you need to create them yourself. A more appropriate way to create that property would be to do something like this:

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

However, since you're not doing anything other than setting and returning _contents in your setter and getter, you can simplify it down to this:

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

    }
}

Note: contents might also be a good candidate for using an optional (String?) and setting it to nil rather than initializing it to an empty string.