Overriding getter in Swift

29,485

Solution 1

This works for me:

public class MyBaseClass {
    private var _name: String = "Hi"
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super._name = newValue
        }
    }
}

MyDerivedClass().name

EDIT

This code works for me in a playground, placing it in the Sources -> SupportCode.swift file

public class MyBaseClass {
private var _name: String = "Hi"
public internal(set) var name: String {
    get {
        return self._name
    }
    set {
        self._name = newValue
    }
}
public init() {

}

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           // do nothing
        }
    }
   public override init() {

    }
}

It's a bit of a bodge because I get the same warning as you that internal(set) cannot be placed before the overridden subclass variable. It may well be a bug. And also I'm cheating to make sure the setter of the derived class does nothing.

A more common use of internal(set) or private(set) is to have code like this, which is similar to that in the documentation:

public class MyBaseClass {
    public private(set) var _name: String = "Hi"
    public var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           super._name = newValue
        }
    }
   public override init() {

    }
}

Here the setter can be read directly with MyDerivedClass()._name but it cannot be altered, e.g. this MyDerivedClass()._name = "Fred" would raise an error but MyDerivedClass().name = "Fred" would be OK.

Solution 2

Problem 1

MyBaseClass does not compile because:

  1. it has a stored property (_name)
  2. this stored property is non optional so it cannot be nil
  3. there is no initializer to populate it

So first of all we need to add a proper initializer to MyBaseClass

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get { return self._name }
        set { self._name = newValue }
    }
    init(name : String){
        _name = name
    }
}

Problem 2

Now we can declare MyDerivedClass that overrides the computed property:

  1. we need to use the magic keyword override
  2. we need to provide both the setter and the getter

Here's the code:

public class MyDerivedClass: MyBaseClass {
    public override var name: String {
        get { return "Derived - \(super.name)" }
        set { super.name = newValue }
    }
}

Test

From my playground:

let somethingWithAName = MyDerivedClass(name: "default name")
println(somethingWithAName.name) // > "Derived - default name"
somethingWithAName.name = "another name"
println(somethingWithAName.name) // > "Derived - another name"
Share:
29,485
BPCorp
Author by

BPCorp

Updated on April 09, 2020

Comments

  • BPCorp
    BPCorp about 4 years

    I have a situation where I need to override the getter of a property.

    Let's say we have:

    public class MyBaseClass {
        private var _name: String
        public internal(set) var name: String {
            get {
                return self._name
            }
            set {
                self._name = newValue
            }
        }
    }
    

    Nothing really fancy, I guess.

    Now, if I try to override the getter in a derived class:

    public class MyDerivedClass: MyBaseClass {
        public var name: String {
            get {
                return "Derived - \(super.name)"
            }
        }
    }
    

    I get the compile error: Cannot override mutable property with read-only property 'name'.

    If I try to add the setter and overriding it:

    public class MyDerivedClass: MyBaseClass {
        public internal(set) var name: String {
            get {
                return "Derived - \(super.name)"
            }
            set {
                super.name = newValue
            }
        }
    }
    

    I get the error: Setter of overriding var must be as accessible as the declaration it overrides.

    And if I try the following:

    public class MyDerivedClass: MyBaseClass {
        public internal(set) var name: String {
            get {
                return "Derived - \(super.name)"
            }
        }
    }
    

    Then, the compiler crashes...

    How can I achieve to override only the getter ?