Skip to content

[SR-5816] KeyPath-based KVO: Unable to stop observing owned object on deinit #3809

Description

@antonvmironov
Previous ID SR-5816
Radar None
Original Reporter @antonvmironov
Type Bug
Environment

Version 9.0 beta 6 (9M214v)

Additional Detail from JIRA
Votes 7
Component/s Foundation
Labels Bug
Assignee None
Priority Medium

md5: cc033b62e7f6826a74055dc7ea71bfeb

Issue Description:

MyHostObject owns MyObject and observes changes of it's value:

import Foundation

class MyObject: NSObject {
  @objc dynamic var value: Int = 0
}

class MyHostObject: NSObject {
  @objc dynamic let myObject = MyObject()
  var _observation: NSKeyValueObservation?

  override init() {
    super.init()
    _observation = observe(\.myObject.value, options: [.new]) { (myObject, change) in
      print("value changed to \(change.newValue!)")
    }
  }

  deinit {
    // `myObject` is in Limbo right now, but I can still call it's methods and, hopefully, remove observation
    _observation?.invalidate()
    _observation = nil
  }
}

var myHostObject: MyHostObject? = MyHostObject()
myHostObject = nil // crashing here with:
// *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x101c10290 of class issue_NSKeyValueObservation.MyHostObject was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x101c14ed0> (
<NSKeyValueObservance 0x101c14c20: Observer: 0x101c115f0, Key path: myObject.value, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x101c129b0>
)'

With Objective-C equivalent, MyHostObject would still be able to remove observation from myObject.

This is happening because NSKeyValueObservation holds a weak reference to an object. That weak reference turns to nil too soon. My suggestion is to use unowned or Unmanaged<MyObject> reference.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions