Using Getters and Setters to Modify Values W/O Subclassing in Swift

Using Getters and Setters to modify values w/o Subclassing in Swift

If you use set and get then the property must be computed. There is no actual storage for it.

This code defines a var to hold the data and a computed var to handle the access. This is similar to what you had in Objective-C (except that in Objective-C you could "hide" the actual variable by making it private or, more recently, having it synthesized an never mentioned in the header).

class File {
// this stores the actual data, do not access it directly, consider it private
var theFileName: String = ""

// this is the real interface
var fileName: String {
get {
return self.theFileName
}
set(name) {
self.theFileName = name + ".fileType"
}
}
}

You can also write the set like this:

set {
self.theFileName = newValue + ".fileType"
}

where newValue is the default name if you omit the argument declaration for set.

But what you probably want to do is what you already did (and rejected for unknown reasons):

var fileName: String = "" {
didSet {
self.fileName += ".fileType"
}
}

This is the correct way.

Note that "I must wait until the value is already set before I can modify it." is not true. It looks like that, but the compiler can very well optimize the code (and probably will).

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

How can I change the property value in subclass within swift?

In your real example:

  • Vehicle currentSpeed is a stored property. That means you can assign to it directly and the property value changes.

  • AutomaticCar currentSpeed is effectively a different property — a computed property. That means that when you assign to it, all that happens is that the set function runs. No stored property values change as a result, unless you change them, right here, in the set function.

Well, in your AutomaticCar's currentSpeed set function, you didn't store the new value in the stored property, Vehicle's currentSpeed. Therefore it didn't change, because nothing happened that would change it.

As Hamish rightly says in a comment, what you meant to say is probably this:

class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
self.gear = Int(self.currentSpeed/10) + 1
}
}
}

In that formulation, AutomaticCar currentSpeed is not a computed property; it is Vehicle currentSpeed — it is the very same stored property, along with a setter observer. So setting it sets it, storing the new value — plus now we run the setter observer and make the change in self.gear that you are after.

Note that the override of a stored property in a subclass must be one or the other, either an independent computed property or else the original stored property with the addition of a setter observer. It cannot of itself be an independent stored property.

Modify getter without modifying setter in Swift

Try this out:

var channel: String? {
get {
return self["channel"] as? String
}
set {
self["channel"] = newValue
}
}

How can a operate with value of setter in structs?

It is called Shorthand Setter Declaration.

Cited from Swift 3 book:

If a computed property’s setter does not define a name for the new
value to be set, a default name of newValue is used.

If you would like to have a better readable format, you could use this:

...
set (newItems) { //add your own variable named as you like
let result = String(newItems * 100)
allResults.append(result)
}
...

How to change Swift property visibility in subclass

Swift has two types of properties: stored properties and computed properties. You can override both of them but the overriden version cannot be a stored property, you have to override using computed properties.

Note that a stored property is just a chunk of memory but a computed property is a set of two methods - a getter and a setter. You cannot override a chunk of memory with another chunk of memory but you can override a method.

See Inheritance - Overriding, section Overriding Properties

You can override an inherited instance or type property to provide your own custom getter and setter for that property, or to add property observers to enable the overriding property to observe when the underlying property value changes.

You can provide a custom getter (and setter, if appropriate) to override any inherited property, regardless of whether the inherited property is implemented as a stored or computed property at source. The stored or computed nature of an inherited property is not known by a subclass—it only knows that the inherited property has a certain name and type. You must always state both the name and the type of the property you are overriding, to enable the compiler to check that your override matches a superclass property with the same name and type.

You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property.

And a Note: under

If you provide a setter as part of a property override, you must also provide a getter for that override. If you don’t want to modify the inherited property’s value within the overriding getter, you can simply pass through the inherited value by returning super.someProperty from the getter, where someProperty is the name of the property you are overriding.

which tells us exactly what to do:

public class MyClass: MyBaseClass {
public override var abc: Int {
get {
return super.abc
}
set {
super.abc = newValue
}
}
}

Note that the following would also work. We just have to make sure we have a computed property:

public class MyClass: MyBaseClass {
public override var abc: Int {
didSet {
}
}
}

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 a stored property in Swift

Why am I not allowed to just give it another value?

You are definitely allowed to give an inherited property a different value. You can do it if you initialize the property in a constructor that takes that initial value, and pass a different value from the derived class:

class Jedi {
// I made lightSaberColor read-only; you can make it writable if you prefer.
let lightSaberColor : String
init(_ lsc : String = "Blue") {
lightSaberColor = lsc;
}
}

class Sith : Jedi {
init() {
super.init("Red")
}
}

let j1 = Jedi()
let j2 = Sith()

print(j1.lightSaberColor)
print(j2.lightSaberColor)

Overriding a property is not the same as giving it a new value - it is more like giving a class a different property. In fact, that is what happens when you override a computed property: the code that computes the property in the base class is replaced by code that computes the override for that property in the derived class.

[Is it] possible to override the actual stored property, i.e. lightSaberColor that has some other behavior?

Apart from observers, stored properties do not have behavior, so there is really nothing there to override. Giving the property a different value is possible through the mechanism described above. This does exactly what the example in the question is trying to achieve, with a different syntax.



Related Topics



Leave a reply



Submit