swift 4 observe with @IBOutlet objects

I'd like to observe @IBOutlet NSPopUpButton property using swift 4.

But completion is never called.

I've tried with other NSPopUpButton keypaths \.indexOfSelectedItem, \.numberOfItems, but result is the same.

Local class properties observetion work.

Any ideas what i'm missing ?


class AppDelegate: NSObject, NSApplicationDelegate {
  @IBOutlet @objc dynamic weak var platformPopUpButton: NSPopUpButton!
  var observation: NSKeyValueObservation?
  func applicationDidFinishLaunching(_ aNotification: Notification) {
   observation = platformPopUpButton.observe(\NSPopUpButton.titleOfSelectedItem, options: [.new,.old]) { (popUpButton, changeType) in
   print("value changed \(popUpButton.titleOfSelectedItem)")
   }
  }
 }

}

To which object do you connect the IBOutlet ?

platformPopUpButton

Not all properties are observable. If you want to detect value change events of an NSPopUpButton, add an action target to it.

By the way, why are you putting an @IBOutlet on the AppDelegate?

Of course !


but where is this object (in which viewController) ?

This is sample app with default new single view project settings.

I have not found view controller

sample project

screenshot

This is an OSX App, exact ?


You should see a window in the storyboard, with its window controller.


The PopupButton should be defined in this window and its IBOutlet in the associated code of the ViewController.

i've included link to sample project and it's being moderated

i'll let You know when.

I see messsage is already there with sample project.

Please take a look.


Thank You

OK. Moderation may take a few days !

do You see post above with links ?

Accepted Answer

Received.


I tested, and get the message

value changed <testCombomBox.AppDelegate: 0x6080000a28e0>

whatever

So the first observer works.


For the second, where do you see that numberOfItems changes ?


I have modified like this and get a message:

observation = platformPopUpButton.observe(\NSPopUpButton.numberOfItems, options: [.initial, .new,.old]) { (popUpButton, changeType) in

print("number changed \(popUpButton.titleOfSelectedItem)")

}


number changed Optional("")


So, you should check your options [.new,.old] : you never meet those conditions


Here is the code that I slightly changed and tested

    func applicationDidFinishLaunching(_ aNotification: Notification) {
       // Insert code here to initialize your application

       platformKeysObservation = observe(\.platformKeysValue, options: [.new,.old]) { (object, changeType) in
            print("value changed \(object)")     
            }

       observation = platformPopUpButton.observe(\NSPopUpButton.numberOfItems, options: [.initial, .new,.old]) { (popUpButton, changeType) in
            print("number changed \(popUpButton.titleOfSelectedItem)")     
       }

       let platformValues = WDPlatform.allCases.map { $0.rawValue }
       platformPopUpButton.addItems(withTitles: platformValues)

  }

But I also see in your project that there is a binding defined for selectedvalue, but none defined for numberOfItems. And I'm not sure it is possible.

Binding variable observation always worked.

You're right about .initial option, it triggers right away as expected according to documentation.


I've updated my sample project(same link above).

Added new app target which concentrates only on popUpButton keypath observations.

There are 3 observations for following keypaths:

numberOfItems

indexOfSelectedItem

selectedItem


After each click row is added to popUpButton and expecting every of those observations to trigger,

but none of them do.


Please take a look.


Thank You

KVO is implemented by intercepting the setter method using the dynamic feature of Objective-C.

So, when a property is purely read-only and has no setter method, you would never succeed observing it with KVO method like `observe`.


Why do you insist on using `observe`?

makes sense.

Seems that all of those properties are calculated.


But even calculated properties can be observed and notified on change.

I demonstrated this in my updated sample app using willSet didSet,

it just seems that NSPopUpButton does not follow same path(and why it should?).


Thank You all

dictionary.swift file is missing, no way to test.

swift 4 observe with &#64;IBOutlet objects
 
 
Q