Is there a reason why `didSet` not being called on a weak property that becomes nil?


(Adrian Zubarev) #1

Extending the example from the other thread a little:

class Ref {
  weak var obj: Obj? {
    didSet { print(obj == nil ? "is nil" : "is not nil") }
  }
}

class Obj {
  weak var ref: Ref?

  func unlink(from ref: Ref) {
    print(ref.obj as Any)
  }

  deinit {
    print("deinit")
    ref.map(unlink(from:))
  }
}

var obj: Obj? = Obj()
let ref = Ref()
obj?.ref = ref
ref.obj = obj
obj = nil

The result is:

is not nil
deinit
nil

Why don't we track and fire the didSet observable when the object becomes nil? If there is a technical reason, so be it. However if not then it seems logical to me that the output should look like this:

is not nil
is nil
deinit
nil

(Jordan Rose) #2

If that were the case, that would mean releasing any class could have arbitrary side effects beyond what's in the deinit, because anyone could have made a weak variable referencing it. That's something we try to avoid in Swift.

Beyond that, pure Swift weak properties don't even get set to nil immediately; they do it the next time you load from the property. (This is different from Objective-C weak references.) So there's also not even a place to put a call to the setter today.