Reputation: 964
I would like to keep a variable sync with UserDefaults directly when I set a value. I've done it like this:
var userId: String {
get {
return UserDefaults.standard.string(forKey: kUserIdKey) ?? ""
}
set {
UserDefaults.standard.set(newValue, forKey: kUserIdKey)
}
}
It is working fine but is it the right way to do it?
If so, what about Array?
var tagsList: [Int] {
get {
return (UserDefaults.standard.object(forKey: kTagsList) as? [Int]) ?? [Int]()
}
set {
UserDefaults.standard.set(newValue, forKey: kTagsList)
}
}
If I add an element tagsList.append(0)
, is the new value stored in UserDefaults?
Update.
Here is what I have in the playground:
Upvotes: 1
Views: 407
Reputation: 6058
If I add an element tagsList.append(0), is the new value stored in UserDefaults?
YES.
At a glance, you have a setter and, as a setter, it only observes the value whenever you make a new assignment, like:
tagsList = [1,2,3]
// new value.
If Array<Int>
([Int]
) was class we could say that, even though you do modify the existing array by calling append
, this is not an assignment, per se. However, [Int]
is not a class
, it's a struct
which means that any function that modifies (mutates, to be correct) existing struct
, basically leads to a new assignment. This is the reason why you would see setter to trigger.
Upvotes: 2
Reputation: 1401
Short answer: Yes.
Long answer: Arrays and Strings are struct
s in Swift, which semantically make a whole new copy when mutated.
The newValue
in the setter therefore is the resulting array of whatever mutation you applied to the array, whether it being an append
or other mutating functions.
You can easily verify this behavior in a playground like this:
var array: [Int] {
get { return [1, 2, 3] }
set { print(newValue) }
}
array.append(4)
// Prints [1, 2, 3, 4]
Upvotes: 2