TL;DR: Why, when the array is created together with initial values, the values are de-initialized right away, but filling the array values after the array is created produces different behavior?
I'm learning Swift after JavaScript, which has GC, so the concepts of ARC and de-initialization are somewhat novice for me. To understand it deeper, I've written the following code, based on the example from the official documentation:
// definitions; see the next two snippets for usage
class Bank {
static var coins: Int = 100 {
didSet {
let diff = coins - oldValue
let sign = diff < 0 ? "-" : "+"
print("Bank: \(oldValue) \(sign) \(diff.magnitude) = \(coins)")
}
}
static func give(_ amount: Int, to user: User) {
guard amount <= coins else {
print("[ERROR] The bank does not have enough coins; requested \(amount - coins) more coins than available")
return
}
user.purse += amount
coins -= amount
}
static func take(_ amount: Int, from user: User) {
user.purse -= amount
coins += amount
}
}
class User {
private static var count = 0
let id: Int
var purse = 0
init() {
User.count += 1
id = User.count
}
deinit {
print("User #\(id) perished")
Bank.take(purse, from: self)
}
}
When I create array with existing user instances (array = [value, value]
), the de-initialization happens right after the assignment to nil
(array[0] = nil
):
var users: [User?] = [
User(),
User(),
]
Bank.give(90, to: users[0]!)
users[0] = nil
Bank.give(50, to: users[1]!) // works
// Bank: 100 - 90 = 10
// User #1 perished
// Bank: 10 + 90 = 100
// Bank: 100 - 50 = 50
… but when I first create an empty array and then populate it with values (array = []; array[0] = value; array[1] = value
), de-initialization happens at some random point later:
var users = [User?](repeating: nil, count: 2)
users[0] = User()
users[1] = User()
Bank.give(90, to: users[0]!)
users[0] = nil
Bank.give(50, to: users[1]!) // fails
// Bank: 100 - 90 = 10
// [ERROR] The bank does not have enough coins; requested 40 more coins than available
// User #1 perished
// Bank: 10 + 90 = 100
What is the difference from the compiler point of view? And what is the rationale for this difference?