addObserver:selector:name:object:

The last argument to the method, object, refers to the object from which we want to receive notifications. If I use missing value there, the method works fine, but I do of course receive notifications from all objects. I want to be explicit about which object I want notifications from.

How do I specify the object?
I thought that I would use a property that in IB is bound as an outlet from File’s Owner to the object I am interested in (in my case an NSPopUpButtonCell). That won’t work though!?

Why don’t you use action?

Also a notification of an NSPopUpbuttonCell has only one notification and that is when the menu is going about to be shown. It’s used for ‘lazy’ data which means that the popup button’s menu’s data needs to be updated right before it going to be shown. So unless this is exactly what you need I don’t think notification is needed on an NSPopUpButtonCell at all.

A notification is also not very usable for triggering functions of one object (thats were action are for). For example when you have changed something in your preferences of your application you can ask the app delegate which windows are open and handle them one by one or you can make your own notification that you’ve saved your preferences. All objects that rely on preferences will get an custom notification and react to that notification. This is where notifications are for, so you don’t have to connect all objects.

As I read it, an IBOutlet should do the job. Could it be that the notification is sent by something other than the NSPopUpButtonCell? perhaps you should set it to missing value and log the object of the resulting notification, to be sure.

I am somewhat uncertain as to what you mean? With “action” I assume you mean method or handler, and I already have a “Sent Action” from this popup to File’s Owner. But I don’t see any way of getting a handler called prior to the user selecting an item in the popup, except by a notification?

The reason I need it is for undo/redo: I need to know the value before the user has selected an item in the popup. That value might even be missing value, and I need to know. I am not aware of any other way of picking that information. But if I get a chance to look into the table row before the user has selected a value, then I can easily get the old value.

If I do log sender in the handler to which the notification is connected (using missing value as the object), I get:
NSConcreteNotification 0x2000c7ea0 {name = NSPopUpButtonCellWillPopUpNotification; object = <NSPopUpButtonCell: 0x20082a8a0>}

So, it really is sent by the popup cell. But since it does not work if I replace missing value with the IBOutlet popupInTable, I was thinking that the format of the addObserver_selector_name_object_ might require that the sending object be specified in some special way? I tried adding ‘my’ or ‘current application’ but it makes not difference. I also wondered if the IBOutlet as an AppleScript property didn’t “bridge well” into an argument of addObserver_selector_name_object_?

/Harald

The Objective-C examples I can find all use nil or a typical object, so I can’t see that you’re doing anything wrong. I presume you’ve double-checked the outlet.

Not only double-checked, but triple-checked, or quadruple-checked!

Right now I tested by changing it to an outlet for another popup cell I have in the toolbar, and to my surprise that works! But it is of course not useful for me, since it is the wrong button. It does prove, however, that the principle and syntax works. Somehow, it is the table that stops it from working, i.e it will not work if the popup cell is in a table.

The table has File’s Owner as its delegate. Can it be so that using NSNotificationCenter’s defaultCenter is no good for the table?

I tried this with the “current application’s NSPopUpButtonCellWillPopUpNotification” and missing value as the object. If I log the notification that is sent, the object of that notification is different every time I click on the cell --If I click 5 times on the same cell in the table the log shows:

I’m not sure why this is. You get the same object every time if you do this on a popup button outside a table. Your outlet can only refer to one object, I would think, so that is probably why specifying the object doesn’t work. I assume this has to do with what happens behind the scenes in a table.

In any case, by looking at the notification’s object’s itemArray() you can get at the menu and do what you need to do. Of course, you will get notifications from all the popup cells in your table (or any where else in your interface). You can query the table’s selectedRow() to find out what row was clicked, and respond to the notification only if it’s from a row you care about.

Ric

Nice find, Ric! (Although it doesn’t really solve the problem, it does increase knowledge)

I get the exact same behavior, and I use the exact same coding.
I.e varying object id from the popup in the table but constant object ids from the two popups I have in the toolbar. Really strange!

A hack would be to test on the following boolean:
theNotification’s object’s itemArray()'s objectAtIndex_(0)'s |tag|() as integer is 0
and making sure that only my poup in the table has the tag value 0 for its first item.

That seems to work, but it does feel somewhat like a hack.
Unless someone finds a way to really pinpoint the sending object, this is the approach I will take.

But it makes me curious why the id varies, i.e why it reports a different object at each click?

/Harald

ric,

This is normal behaviour for a table. It’s very useful when subclassing NSCells

Would you care to describe why this is normal behavior for a table?

And does that mean that it is impossible to create useful IBOutlet to an object in a table cell so that it can be referred to?

An added serious problem is that the notification will be sent, not only from every popup button cell in the document (which I can handle with an if-test) but also from every other document that has been open!

I.e, if I open a second document (it’s a document-based project) and then either leave it open or close it, I will get two notifications: one from the document in which I clicked, but also from the other document which might even be closed!. So, the more documents opened, the more “junk” is being sent around. I find that very strange! Can you explain that?

How do I make the notification to be sent/received only from the document in which I clicked?
Or if that’s impossible, how do I pick only the one from the document in which I clicked and ignore all others, preferably with close-to zero performance penalties?

The only thing I can think of now is to test on a table’s clickedRow() which returns -1 for the non-active windows.

On will display cell of the table gets called after a click. So every time Ric is clicking the cell, the cell will immediatly copied and redrawn. The reason for this is for example those nice gradient selection in Mail’s side bar, it’s a new copy and redraw of the cell when you select it or de-select it.

You can do that but the Table is only a cell controller and can’t access cells in a way like ‘give me cell 3 of row 10’. Cell control must be done by subclassing a cell. With table’s will display cell delegate you call the right method of your subclassed cell.

I followed this up with Harald off-line, but for those who are interested: the key is to have only the active document as observer at any time. You do this by adding (and removing) the observer in windowDidBecomeKey_ (and windowDidResignKey_) handlers.