11

Given class Obj,

class Obj: NSObject {
    var x = "x"
}

and its subclass, Obj1, how do you change the default value of var x?

Simply setting a new value would make the most sense, but it seems to error out...

class Obj1: Obj {
    var x = "y"
}

❗️ Cannot override with a stored property 'x'

Patrick Perini
  • 22,555
  • 12
  • 59
  • 88

4 Answers4

9

In most cases, injecting these values via init is the preferred way.

For example:

class Foo
{
    var x : String

    convenience init()
    {
        self.init(x: "x")  // 'x' by default
    }

    init(x: String)
    {
        self.x = x
    }
}

class Bar : Foo
{
    convenience init()
    {
        self.init(x: "y")   // now 'y' by default
    }

    init(x: String)
    {
        super.init(x: x)
    }
}

However, there are some cases where you want to override a computed property or perhaps something that is not exactly initialized.

In this case, you can use the override var syntax:

override var x : String
{
    get { return super.x }      // get super.x value
    set { super.x = newValue }  // set super.x value
}

The above code does not change the behavior, but illustrates the syntax that would allow you to do so.

Erik
  • 12,730
  • 5
  • 36
  • 42
6

This question has been marked answered, but there is also the safe-in-Swift template method pattern by way of delegation to a computed property:

class Foo {
    lazy var x : String = self.defaultX
    var defaultX:String { return "foo" }
}

class Bar : Foo {
    override var defaultX:String { return "bar" }
}


println(Foo().x) // foo
println(Bar().x) // bar

By safer, I am referring to Swift's enforcement of the initialization sequence that prevents problems with "virtual" calls into a not-yet constructed sub class (ie, having a base class call a virtual method that is implemented in a sub class, but before that subclass has finished initializing). This was a danger in C++, for example.

Chris Conover
  • 8,889
  • 5
  • 52
  • 68
3

Define an init() method as:

init () {
  super.init()
  x = "y"
}

You'll want any other initializers in Obj1 to invoke this as self.init(). The Apple documentation has a long discussion on designated initializers and inheritance vis-a-vis initializers.

GoZoner
  • 67,920
  • 20
  • 95
  • 145
1

In swift 3 I've found that chrisco's solution doesn't work anymore, But it works if you declare the variable in the base class with private(set).

class Parent {
    private(set) var name = "Dad"
}

class Child: Parent {
    override var name: String { return "Son" }
}
Felix Dumit
  • 458
  • 3
  • 9