Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding getter in Swift

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 ?

like image 974
BPCorp Avatar asked Apr 30 '15 15:04

BPCorp


People also ask

What is override function in Swift?

Swift version: 5.6. The override is used when you want to write your own method to replace an existing one in a parent class. It's used commonly when you're working with UIViewControllers , because view controllers already come with lots of methods like viewDidLoad() and viewWillAppear() .

Can we override stored property in Swift?

Hi, Swift rules state that any inherited property can be overridden whether it is implemented as a stored or computed property at source (parent class).

Can we override class method in Swift?

In Swift Inheritance, the subclass inherits the methods and properties of the superclass. This allows subclasses to directly access the superclass members. Now, if the same method is defined in both the superclass and the subclass, then the method of the subclass class overrides the method of the superclass.

How do I stop overriding in Swift?

Preventing Overrides You can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the final modifier before the method, property, or subscript's introducer keyword (such as final var , final func , final class func , and final subscript ).


2 Answers

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.

like image 64
sketchyTech Avatar answered Sep 17 '22 09:09

sketchyTech


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" 
like image 35
Luca Angeletti Avatar answered Sep 17 '22 09:09

Luca Angeletti