Override property observer
You can override the set
and get
part of the property and move your println
there. This way Swift won't call the original code -- unless you call super.
class Foo {
private var _something: Int!
var something: Int! {
get {
return _something
}
set {
_something = newValue
println("vroom")
}
}
}
class Bar: Foo {
override var something: Int! {
get {
return _something
}
set {
_something = newValue
println("toot toot")
}
}
}
That's not pretty, though.
Here's a better -- and simpler -- solution:
class Foo {
var something: Int! {
didSet {
somethingWasSet()
}
}
func somethingWasSet() {
println("vroom")
}
}
class Bar: Foo {
override func somethingWasSet() {
println("toot toot")
}
}
Since there is no way to "override" the didSet
, what remains is overriding a secondary function especially created for that purpose.
Swift property observing doesn't override
Inheritance section of The Swift Programming Language (Swift 2.2) describes 'overriding property observers' as 'adding property observers'
Overriding Property Observers
You can use property overriding to add property observers to an
inherited property...
If a subclass were able to override didSet
observer of currentSpeed
property of AutomaticCar
class in the following example:
class AutomaticCar {
var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
The didSet
in the subclass would prevent updating gear
property which could break the designed behavior of the super class, AutomaticCar.
Overriding didSet
I have tried your code in a playground and got and error
Variable with getter/ setter cannot have and initial value.
So I just removed =""
from the orverriding variable. like below:
class Foo {
var name: String = "" { didSet { print("name has been set") } }
}
class Bar: Foo {
override var name: String {
didSet {
print("print this first")
// print the line set in the superclass
}
}
}
let bar = Bar()
bar.name = "name"
and that's what I got in consol:
name has been set
print this first
What is the right way to override a property in a subclass in Swift?
I don't get that error in 6.1, but the underlying problem is you have an infinite loop here. What you meant to say is:
// This is wrong, but what you meant
override var someStoredProperty: Int? {
willSet {
super.someStoredProperty = newValue! + 10
}
}
Note the super
. (Which is yet another reason I strongly recommend using self.
on properties, to make it clear when these infinite loops exist.)
But this code is meaningless. Before setter, you set the value to x + 10
. You then set the value to x
. What you really meant was:
override var someStoredProperty: Int? {
didSet {
if let value = someStoredProperty {
super.someStoredProperty = value + 10
}
}
}
Override property in Swift subclass
Let’s reduce the example:
class BaseClass {
var surname: String? {
didSet { print("BaseClass \(surname)") }
}
}
class SubClass: BaseClass {
override var surname: String? {
didSet { print("SubClass \(surname)") }
}
}
Then:
let object = SubClass()
object.surname = "Jones"
Will produce:
BaseClass Optional("Jones")
SubClass Optional("Jones")
The above is not overriding the stored property, surname
, with another stored property. There is only the stored property of the base class and the subclass is simply adding its own observer to this property. I refer you to The Swift Programming Language: Inheritance: Overriding, which says:
Overriding Property Observers
You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of an inherited property changes, regardless of how that property was originally implemented.
In your example of name
, you are overriding the computed property with the subclasses’ own computed property. Likewise, in your example of telephoneSet
, you are also overriding the method with the subclasses’ own method. But with surname
, you’re not overriding the base classes’ property, but merely letting the subclass add an observer to the base classes’ stored property.
Overriding computed property with stored one
There's no real technical reason why you cannot override a property with a stored property; it has getters and setters (accessors), which can override the accessors of the property to override. It should just be equivalent to overriding with a computed property that then forwards onto a stored property.
However I do foresee one slight complication with allowing this: property observer overrides.
Consider the following example:
class C {
var f: Int {
get { return 5 }
set { print("C says f was set") }
}
}
class D : C {
override var f: Int {
didSet {
print("D says f was set")
}
}
}
let d = D()
print(d.f)
d.f = 7
print(d.f)
// 5
// C says f was set
// D says f was set
// 5
We can override f
's didSet
in D
. In this case, override var f: Int
is essentially treated as a computed property with a getter and setter that forwards onto super
, with an additional call onto the didSet
implementation in the setter.
No actual storage is introduced by D
here. So why is this problematic? Well, how would we tell the compiler that we do actually want storage for f
? Adding an initialiser expression (= 10
) could communicate that, but not all stored properties have default values; most are initialised from the class' designated initialiser. We'd probably need an attribute of some kind, but for such a limited use case, it doesn't seem like a particularly useful change to the language.
The lazy
case is clear-cut because we cannot add property observers to them.
Although that all being said, the particular case you present should also be clear cut; as the base property only has a getter, so there's no property observers to override. I would recommend you file a bug to (hopefully) see what the Swift team have to say about this.
You can always achieve the same result with a computed property override that then forwards onto a stored property though:
class C {
var f: Int {
return 9
}
}
class D : C {
private var _f: Int = 10
override var f: Int {
get { return _f }
set { _f = newValue }
}
}
let d = D()
print(d.f) // 10
d.f = 7
print(d.f) // 7
Mixing Swift Property Observers and Inheritance
The order of the didSet
calls is as expected - each child calls it's willSet
, then calls super, then calls it's didSet
. If you did it with literal calls to super.pause you'd have something like this, which makes the order of the didSet
calls clear:
class A {
var paused:Bool = false
func pause(_ paused:Bool) {
print("Class A will set paused")
self.paused=paused
print("Class A did set paused")
}
}
class B : A {
override func pause(_ paused:Bool) {
print("Class B will set paused")
super.pause(paused)
print("Class B did set paused")
}
}
class C : B {
override func pause(_ paused:Bool) {
print("Class C will set paused")
super.pause(paused)
print("Class C did set paused")
}
}
let testC = C()
testC.pause(true)
Implement variable attribute property observer in Swift
You can make a property like this
var hideLabel: Bool = false {
didSet {
myLabel.isHidden = hideLabel
//SHOW OR HIDE OTHER VIEWS
}
}
By doing this you don't have to use KVO at the same time you can add more controls to hide to show at didSet context.
I Believe this is a simpler way to do such a thing.
Related Topics
How Is a Type-Erased Generic Wrapper Implemented
App Crash on Sign in (Xcode 9.3) Exc_Bad_Access (Code=1, Address=0X1)
Swift: Extract Float from Byte Data
Wait Until an Asynchronous API Call Is Completed - Swift/Ios
Storyboard Tableview with Segues to Multiple Views
What Is the Role of Avcapturedevicetype.Builtindualcamera
Need to Check That Braces in Given Array Are Balanced or Not
How to Detect That Parameter Is a Tuple of Two Arbitrary Types
How to Get the Realy Fixed Device-Id in Swift
How to Change Colour of the Certain Words in Label - Swift 3
How to Create String Split Extension with Regex in Swift
This Class Is Not Key Value Coding-Compliant for the Key Name.'
How Is a Return Value of Anyobject! Different from Anyobject
How to Block Users on Firebase in a Social Media App? for iOS