How to override setter in Swift
What do you want to do with your custom setter? If you want the class to do something before/after the value is set, you can use willSet
/didSet
:
class TheSuperClass {
var aVar = 0
}
class SubClass: TheSuperClass {
override var aVar: Int {
willSet {
print("WillSet aVar to \(newValue) from \(aVar)")
}
didSet {
print("didSet aVar to \(aVar) from \(oldValue)")
}
}
}
let aSub = SubClass()
aSub.aVar = 5
Console Output:
WillSet aVar to 5 from 0
didSet aVar to 5 from 0
If, however, you want to completely change how the setter interacts with the superclass:
class SecondSubClass: TheSuperClass {
override var aVar: Int {
get {
return super.aVar
}
set {
print("Would have set aVar to \(newValue) from \(aVar)")
}
}
}
let secondSub = SecondSubClass()
print(secondSub.aVar)
secondSub.aVar = 5
print(secondSub.aVar)
Console output:
0
Would have set aVar to 5 from 0
0
Overriding getter in Swift
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.
Is there a way to override property setters and getters in Swift?
While researching this question, I actually happened upon my answer, but still figured it should be put here for anyone else with the same question.
Yes, according to the Swift Programming Language documentation's page on Properties, getters and setters can be made in a similar way to how C# tackles the problem:
struct MyParentType {
var myPlainVar: MyType = MyType()
var myCustomGetterVar: MyType {
// do more stuff
return self.myCustomGetterVar
}
var myCustomGetterSetterVar: MyType {
get {
// do more stuff
return self.myCustomGetterSetterVar
}
set {
// do stuff
self.myCustomGetterSetterVar = newValue
// do more stuff
}
}
var myCustomFancyVar: MyType? {
willSet {
// do stuff with newValue
}
// actual setting is done automatically, so no set{}
didSet {
// do more stuff with oldValue
}
}
}
Note that variables with didSet
must be initialized or optional, and cannot have a get
, since properties which are computed with get
can easily implement their own didSet
and willSet
if they so choose.
Swift override all setters and getters of a subclass
There is one hack to kind of attain what the poster is looking for, however possibly not advisable... Anyway; you can can create your own assignment operators that does whatever you want to do in realm prior to assigning the values
class MyType {
var myInt : Int = 0
var myString : String = ""
init(int: Int, string: String) {
myInt = int
myString = string
}
}
infix operator === {}
func ===<T>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return rhs
}
protocol MyAddableTypes {
func + (lhs: Self, rhs: Self) -> Self
}
extension String : MyAddableTypes {}
extension Int : MyAddableTypes {}
infix operator +== {} // ... -== similarily
func +==<T: MyAddableTypes>(lhs: T, rhs: T) -> T? {
Realm() // replace with whatever Realm()-specific stuff you want to do
return lhs+rhs
}
func Realm() {
// ...
print("Called realm")
}
var a = MyType(int: 1, string: "foo")
a.myString === "bar" // calls Realm(). After operation: a.myString = "bar"
a.myInt +== 1 // calls Realm(). After operation: a.myInt = 2
I thought I'd also mention that if you only want to do "Realm stuff" when a value is set (from your example: prior to setting a value, specifically), then the willSet
method, used with stored properties, doesn't need to look so messy (nested closures), and personally, I would prefer this method
func Realm() {
print("Called realm")
}
class MyType {
// This isn't so messy, is it?
var myInt : Int = 0 { willSet { priorToSetValue(newValue) } }
var myString : String = "" { willSet { priorToSetValue(newValue) } }
var myDouble : Double = 0.0 { willSet { priorToSetValue(newValue) } }
private func priorToSetValue<T> (myVar: T) {
// replace with whatever Realm()-specific stuff you want to do,
// possibly including doing something with your new value
Realm()
}
init(int: Int, double: Double, string: String) {
myInt = int
myDouble = double
myString = string
}
}
var a = MyType(int: 1, double: 1.0, string: "foo")
a.myString = "bar"
print(a.myString) // calls Realm(). After operation: a.myString = "bar"
a.myInt += 1 // calls Realm(). After operation: a.myInt = 2
Override a setter in swift
By writing this...
set(suit) {
self.suit = suit
}
... you introduce an infinite loop, because you call the setter from within the setter.
If your property isn't computed, you should take advantage of willSet
and didSet
notifiers to perform any additional work before/after the property changes.
By the way, you should remove te getter as well. It will cause another infinite loop when accessing the property.
How to override readonly property in Swift subclass, make it read-write, and assign to superclass?
super.inputAccessoryViewController
is not settable.
Your overridden implementation in the subclass, self.inputAccessoryViewController
is.
By adding a setter to the property in a subclass, you don't automatically also add the same thing in the superclass. What's in the subclass stays in the subclass.
So it's not that you can't override a property by adding a setter, you just can't set this here:
override var inputAccessoryViewController: UIInputViewController? {
get { super.inputAccessoryViewController }
set { super.inputAccessoryViewController = newValue }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
You can do other things, like:
override var inputAccessoryViewController: UIInputViewController? {
get { super.inputAccessoryViewController }
set { print("I just go set to \(newValue)") }
}
But that's not very useful. What you want is probably:
private var myInputAccessoryController: UIInputViewController?
override var inputAccessoryViewController: UIInputViewController? {
get { myInputAccessoryController }
set { myInputAccessoryController = newValue }
}
How can I override a setter from a SuperClass in Swift with Xcode 6.3 Beta2?
If all we want it do some extra functionality after the selected
property as been set, we can simply override to add a property observer:
override var selected: Bool {
didSet {
if self.selected {
// do something
}
}
}
Updated Answer for Swift 5:
override var isSelected: Bool {
didSet {
if self.isSelected {
// do something
}
}
}
If we care about what the previous value of selected
was, we can access it via oldValue
:
didSet {
if self.selected == oldValue {
return
}
// do something
}
Updated Answer for Swift 5:
didSet {
if self.isSelected == oldValue {
return
}
// do something
}
And don't forget, we can use willSet
as well if we need to do something just before the value is changed.
I was curious what would happen when we've got a large hierarchy of classes each adding their own stuff in willSet
and didSet
property observers, so I created the following test:
class ClassA {
var _foo: Int = 0
var foo: Int {
set(newValue) {
println("Class A setting foo")
self._foo = newValue
}
get {
return self._foo
}
}
}
class ClassB: ClassA {
override var foo: Int {
willSet {
println("Class B will set foo")
}
didSet {
println("Class B did set foo")
}
}
}
class ClassC: ClassB {
override var foo: Int {
willSet {
println("Class C will set foo")
}
didSet {
println("Class C did set foo")
}
}
}
Now, if we create an object of ClassC
and set its foo
property:
var c: ClassC = ClassC()
c.foo = 42
We get the following output:
Class C will set foo
Class B will set foo
Class A setting foo
Class B did set foo
Class C did set foo
So, it's important to note a few things from this...
- A child class's
willSet
is called before its parent'swillSet
. - A child class's
didSet
is called after its parent'sdidSet
. - Creating an override for the sake of adding property observers does not replace any property observers in the parent classes.
The first two points make a bit of sense. And actually, this makes property observers much more appealing. Effectively, Swift forces our hand into going up and down the heirarchy in the appropriate manner and nicely splits it out into two separate methods. Swift also prevents us (I believe) from overriding a parent class's property, but also still lets us observe changes to that property--this is much better than Objective-C's approach.
But the third point is probably the most important. Be careful--you can easily get bogged down in a massive heirarchy of didSet
and willSet
code that's slowing down what should be a pretty quick process: setting a property's value.
Related Topics
How to Create Generic Convenience Initializer in Swift
Tableview.Cellforrowatindexpath(Indexpath) Return Nil
How to Get The Count of a Type Conforming to 'sequence'
Can't Load Images on MAC Screensaver Release Build (It Works on Xcode Debug Build)
Easiest Way to Truncate Float to 2 Decimal Places
Why I Can Not Use Setvalue for Dictionary
How to Check If a Variable Is Nil
Nil Cannot Be Assigned to Type Avcapturedeviceinput
How to Define a Variable in a Swift If Statement
Difference Between Firinstanceid.Instanceid().Token() and Messaging.Messaging().Fcmtoken
Filtering Realm Objects with Swift
Why Would One Use Nested Classes
How to Test If an Instance Is a Specific Class or Type in Swift
Keyboard Height Change Observer Swift
Iocreateplugininterfaceforservice Returns Mysterious Error
Swift iOS14 Datepicker Text Alignment
How to Get The Push Notifications Displayed in The Notification Center