Reputation: 5082
Let's start with some code segments
struct DigitS {
var number = 42
init(_ n: Int) {
self.number = n
}
mutating func replace() {
self = DigitS(12) // mutating
}
}
class DigitC {
var number = 42
init(_ n: Int) {
self.number = n
}
func replace() {
self = DigitC(12) //#Cannot assign to value: "self" is immutable
}
}
For a very long time, I was very confused about the meaning of mutable, modifiable. Here are some of my understandings so far, would be nice if you can point out all errors it may have
Mutating function in the structure type above does not "mutates" the instance, it will replace the old value of the variable by a totally new one
Mutating means: the action like assignment, initialization or mutating function does not modifies the current value but a triggers a replacement
A class typed variable's value is immutable, but you can modify/change the current value (this is the reason the compiler gives out the warning, please see the comments with #)
The setter observer, can only be called if the type is a value type, because setter tells if the variable has been mutated/replaced (please see code below)
struct Digit {
var number = 12
}
var b = Digit() {
didSet{ print("number is set") }
}
b.number = 22 // observer is called
class Digit {
var number = 12
}
var b = Digit() {
didSet{ print("number is set") }
}
b.number = 22 // observer is not called
Thanks for your time and help
Upvotes: 0
Views: 2517
Reputation: 5082
The observer observes the value change, the value of a class typed variable is the reference points to the object. To trigger the property observer, the reference has to be changed.
class Digit {
var number = 12
}
var a = Digit()
var b = Digit() {
didSet{ print("number is set") }
}
b.number = 22 // observer is called
b = a //observer is called here!!
Upvotes: 0
Reputation: 7746
Dealing with memory tend be better explained using images, but I'll give it a go here:
Given a simple struct with a mutator:
struct Example {
var text: String
mutating func changeText(to newText: String) {
self.text = newText
}
}
let constantExample = Example(text: "Test") //Makes a section of memory that isn't allowed to change.
constantExample.changeText(to: "Other Test") //This doesn't work because constantExample isn't mutable.
var mutableExample = Example(text: "Test") //Makes a section of memory that is allowed to change.
mutableExample.changeText(to: "Other Test") //This doesn't make a new copy, but rather changes the value in mutableExample's section of memory
If you were to use the specific case you mentioned:
mutating func changeText(to newText: String) {
self = Example(text: "A new text")
}
mutableExample will still reside in the same memory location, but you are manually Creating a completely new instance of the Example and then copying that data from that instance to mutableExample.
The opposite :) Mutating changes the instance in-place. You can change that instance by copying a different value, (as happens in the self =
example), but the instance is still the same instance, just with a different value.
When creating a class variable, you are creating a reference to a section of memory. When setting or changing that reference var variableName = classInstance
the location of reference remains the same once initialized, but the location being referenced (if a var) can then change.
You're functionally correct, but missing some nuance. In the struct example, as previously stated the actual value of the instance is changing. In the class example, the referenced memory is changing, but the actual value stored within b
does not change.
Upvotes: 2