What Are 'Get' and 'Set' in Swift

Swift Protocols: Difference between { get } and { get set } with concrete examples?

protocol — is a requirement of some minimal interface of the type implementing it.

  • var name: Type { get } requires type to have property with at least a getter (accessible from outside of the type, not private), i.e. outside code should be able to read value of the property. In the implementing type it could be let name: Type, var name: Type, private(set) var name: Type, fileprivate(set) var name: Type, etc.

  • var name: Type { get set } requires type to have property with both accessible getter and setter, i.e. outside code should be able to read and write to the property. Here only var name: Type would be allowed.

If protocol requires for getter but you also provide a setter — it's not against protocol requirements.
But if protocol requires for both getter and setter — you must provide both, and not having any of them won't be valid implementation.


Your Person class defined both properties as var(with accessible getter and setter) therefore you can change them both. But PersonProtocol haven't required ability to set firstName.

And as @JoakimDanielson shows, if you will use just interface required by protocol you won't be to change the firstName value.

Difference between 'get' and 'get set' in Swift

This protocols requires conforming types (classes, structs or enums) to have two properties:

  1. numberOfWheels, which must provide at least a getter. This means it's either a let property, a var property, or a computed property with at least a getter (the setter is optional).

  2. wheelSize, which must provide a getter and a setter. This means it has to be either a var property, or a computer property with both a getter and a setter.

Swift correct use of getters and setters

Swift provides a much more structured approach to getters and setters than Java.

You can, but you should not, write setters and getters as you did in your code.

Instead (if you are using stored properties) just declare the property with a visibility non private (e.g. internal in my example). This way callers outside of your class will be able to see the property and change it.

class Person {

var name: String {
willSet(newValue) {
print("\(self.name) is going to be renamed as \(newValue)")
}
didSet(oldValue) {
print("\(oldValue) has been renamed as \(self.name)")
}
}

init(name: String) {
self.name = name
}
}

Ok but in java getter and setters do allow me to add custom logic to be executed before or after the value is changed.

Right! In Swift, you can do this using the willSet and didSet observers.

willSet(newValue)

You write here the code you want to run before a new value is written in the property.
Here you can access the current value (that is going to be overwritten) with self.name while the new value is available with newValue.

didSet(oldValue)

You write here the code you want to run after a new value is written in the property.
Here you can access the old value (that has been overwritten) with oldValue while the new value is available in self.name.

Both willSet and didSet are optional [I am not talking about Optional Type! I mean you are not forced to write them :)].

If you don't need to run some code just before or after the property has been changed, just omit them.

Example

let aVerySmartPerson = Person(name: "Walter White")
aVerySmartPerson.name = "Heisenberg"

// > Walter White is going to be renamed as Heisenberg
// > Walter White has been renamed as Heisenberg

Property getters and setters

Setters and Getters apply to computed properties; such properties do not have storage in the instance - the value from the getter is meant to be computed from other instance properties. In your case, there is no x to be assigned.

Explicitly: "How can I do this without explicit backing ivars". You can't - you'll need something to backup the computed property. Try this:

class Point {
private var _x: Int = 0 // _x -> backingX
var x: Int {
set { _x = 2 * newValue }
get { return _x / 2 }
}
}

Specifically, in the Swift REPL:

 15> var pt = Point()
pt: Point = {
_x = 0
}
16> pt.x = 10
17> pt
$R3: Point = {
_x = 20
}
18> pt.x
$R4: Int = 10

How to call a method once two variables have been set

You could make your properties optional and check they both have values set before calling your function.

var varA: String? = nil {
didSet {
if varA != nil && varB != nil {
myFunc()
}
}
}

var varB: String? = nil {
didSet {
if varA != nil && varB != nil {
myFunc()
}
}
}

Or you can call your function on each didSet and use a guard condition at the start of your function to check that both of your properties have values, or bail out:

var varA: String? = nil {
didSet {
myFunc()
}
}

var varB: String? = nil {
didSet {
myFunc()
}
}

func myFunc() {
guard varA != nil && varB != nil else { return }
// your code
}


Related Topics



Leave a reply



Submit