User interface validation doesn't work, right?
-
For years, the "Implementing Validation" section of Apple's "User
Interface Validation" document has said the following:
"Before it is displayed, a user interface item checks to see if its
target implements validateUserInterfaceItem:. If it does, then the
enabled status of the item is determined by the return value of the
method. You can therefore conditionally enable or disable an item by
implementing validateUserInterfaceItem: in the target object."
This has never been true. Right?
My custom window controller implements the action method for a button,
so it is the button's target, and it also implements -
validateUserInterfaceItem:, all according to the User Interface
Validation document. But my -validateUserInterfaceItem: method is
never called.
If I want it to be called automatically, by analogy to -
validateMenuItem:, I have to override NSWindow's -update method, by
analogy to -[NSMenu update]. In my override of -update, I have to do
for myself what the document claims already happens -- or I have to
observe NSWindow's -NSWindowDidUpdateNotification. Right?
--
Bill Cheeseman
<bill...> -
On Jul 1, 2009, at 2:24 PM, Bill Cheeseman wrote:> For years, the "Implementing Validation" section of Apple's "User
> Interface Validation" document has said the following:
> "Before it is displayed, a user interface item checks to see if its
> target implements validateUserInterfaceItem:. If it does, then the
> enabled status of the item is determined by the return value of the
> method. You can therefore conditionally enable or disable an item by
> implementing validateUserInterfaceItem: in the target object."
> This has never been true. Right?>
It depends on the sort of user interface element.
This does work for menu items and tab bar items...Please file a documentation enhancement request to clarify.
mmalc -
On Jul 1, 2009, at 3:24 PM, Bill Cheeseman wrote:> For years, the "Implementing Validation" section of Apple's "User
> Interface Validation" document has said the following:
>
> "Before it is displayed, a user interface item checks to see if its
> target implements validateUserInterfaceItem:. If it does, then the
> enabled status of the item is determined by the return value of the
> method. You can therefore conditionally enable or disable an item by
> implementing validateUserInterfaceItem: in the target object."
>
> This has never been true. Right?
No, I would say it is usually true, but not always.> My custom window controller implements the action method for a
> button, so it is the button's target, and it also implements -
> validateUserInterfaceItem:, all according to the User Interface
> Validation document. But my -validateUserInterfaceItem: method is
> never called.
Implementing the action method isn't sufficient, BTW. The object must
also be the current target (i.e. first responder for nil-targeted
actions, or designated target). Also note that not all user interface
items do this--they must conform to the NSValidatedUserInterfaceItem
(or NSUserInterfaceValidations) protocol, which IIRC NSButton does
not. In fact, I think only menu items and toolbar items do.> If I want it to be called automatically, by analogy to -
> validateMenuItem:, I have to override NSWindow's -update method, by
> analogy to -[NSMenu update]. In my override of -update, I have to do
> for myself what the document claims already happens -- or I have to
> observe NSWindow's -NSWindowDidUpdateNotification. Right?
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jul 1, 2009, at 7:00 PM, Keary Suska wrote:>> This has never been true. Right?
>
> No, I would say it is usually true, but not always.
I would like very much to see a project in which it does work. The
documentation certainly says it works, but my efforts to make it work
suggest that the documentation is wrong. Have you ever seen a project
in which it works, or are you just relying on the documentation?>> My custom window controller implements the action method for a
>> button, so it is the button's target, and it also implements -
>> validateUserInterfaceItem:, all according to the User Interface
>> Validation document. But my -validateUserInterfaceItem: method is
>> never called.
>
> Implementing the action method isn't sufficient, BTW. The object
> must also be the current target (i.e. first responder for nil-
> targeted actions, or designated target). Also note that not all user
> interface items do this--they must conform to the
> NSValidatedUserInterfaceItem (or NSUserInterfaceValidations)
> protocol, which IIRC NSButton does not. In fact, I think only menu
> items and toolbar items do.
My controller is the target, which according to Apple's documentation,
and according to my understanding for many years, means simply that it
implements the button's action method. My controller does in fact
implement the action method. In addition, my controller is in the
responder chain, which is demonstrated by the fact that the action
method, which is connected to the First Responder proxy in Interface
Builder, executes correctly when I click the button. Also, I declare
the controller to conform to the NSUserInterfaceValidations protocol,
which it does because it implements the -validateUserInterfaceItem:
method. NSButton does conform to the NSValidatedUserInterfaceItem
protocol, as its header file confirms, and it does implement the -
action: and -target: methods required by that protocol.
So I think you are claiming this works because the documentation says
so. I'm saying the documentation is wrong because it doesn't work. I
would love to see a project proving me wrong. Can you show me one?
It does work if you've implemented a menu item that calls the same
action method, because the menu item validation protocol works as
advertised. That is, it falls back on -validateUserInterfaceItem: if
you don't implement -validateMenuItem. Toolbar item validation also
works, because, like menu item validation, it is wired to do so. So
don't send me any projects showing that menu items and toolbar items
work correctly. My complaint is that this technique doesn't work for
user interface items other than menu items and toolbar items, and that
the documentation claiming it does work is wrong.
--
Bill Cheeseman
<bill...> -
On Jul 1, 2009, at 5:56 PM, mmalc Crawford wrote:> It depends on the sort of user interface element.
> This does work for menu items and tab bar items...
Hi, mmalc. It works perfectly well with menu items and toolbar items
because they're specially coded to make it work. The docs are clear
about that, and they're correct.
But it doesn't work at all for user controls in general, and the docs
are misleading (i.e., wrong) about that.
Unless I'm overlooking something. I'm not overlooking anything, am I?
--
Bill Cheeseman
<bill...> -
Bill Cheeseman wrote:> For years, the "Implementing Validation" section of Apple's "User
> Interface Validation" document has said the following:
>
> "Before it is displayed, a user interface item checks to see if its
> target implements validateUserInterfaceItem:. If it does, then the
> enabled status of the item is determined by the return value of the
> method. You can therefore conditionally enable or disable an item by
> implementing validateUserInterfaceItem: in the target object."
>
> This has never been true. Right?
It appears that it only for UI items that conform to
NSValidatedUserInterfaceItem. -
On Jul 1, 2009, at 5:27 PM, Bill Cheeseman wrote:> My controller is the target, which according to Apple's
> documentation, and according to my understanding for many years,
> means simply that it implements the button's action method. My
> controller does in fact implement the action method. In addition, my
> controller is in the responder chain, which is demonstrated by the
> fact that the action method, which is connected to the First
> Responder proxy in Interface Builder, executes correctly when I
> click the button. Also, I declare the controller to conform to the
> NSUserInterfaceValidations protocol, which it does because it
> implements the -validateUserInterfaceItem: method. NSButton does
> conform to the NSValidatedUserInterfaceItem protocol, as its header
> file confirms, and it does implement the -action: and -target:
> methods required by that protocol.
>
> So I think you are claiming this works because the documentation
> says so. I'm saying the documentation is wrong because it doesn't
> work. I would love to see a project proving me wrong. Can you show
> me one?
No, I am saying that it works as advertised for objects that it works
for. NSButton is not one of them, and never has been. You seem to
assume that all user interface items should, but they don't, and never
have, and the documentation has never said that they did. The
documentation is explicit:
"The protocols NSUserInterfaceValidations and
NSValidatedUserInterfaceItem provide a standard way to validate user
interface itemsâthat is, to set their state as appropriate for the
current application context"
Validation is not a function of user interface items, it is a function
of the protocol(s) listed. Neither NSButton, nor any of its parents
conforms to the protocol, so none of them support validation of this
kind. Look at NSMenuItem, and you will see that it does, and that your
validation method will always be called.
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jul 1, 2009, at 6:15 PM, Keary Suska wrote:> No, I am saying that it works as advertised for objects that itThe documentation does state that, and the reference for
> works for. NSButton is not one of them, and never has been. You seem
> to assume that all user interface items should, but they don't, and
> never have, and the documentation has never said that they did. The
> documentation is explicit:
> "The protocols NSUserInterfaceValidations and
> NSValidatedUserInterfaceItem provide a standard way to validate user
> interface itemsâthat is, to set their state as appropriate for the
> current application context"
>
NSValidatedUserInterfaceItem further states:
"The NSValidatedUserInterfaceItem protocol works with
theNSUserInterfaceValidations protocol to enable or disable a control
automatically, depending on whether any responder in the responder
chain can handle the controlâs action method. The NSMenuItem and
NSToolbarItem classes implement this protocol."
<http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Pro
tocols/NSValidatedUserInterfaceItem_Protocol/Reference/Reference.html#//app
le_ref/occ/intf/NSValidatedUserInterfaceItem>
so...
On Jul 1, 2009, at 4:33 PM, Bill Cheeseman wrote:> But it doesn't work at all for user controls in general, and the
> docs are misleading (i.e., wrong) about that.
>
although I'm not sure I'd agree with Bill that the docs are *wrong*,
they certainly could be more helpful in making it clear what the
limitations are, so I'd still suggest filing an enhancement request.
(Hmm, or appending to '<rdar://problem/2801472> UIValidation: Need a
bit more context', which is easily old enough to go to Summer Camp
this year...)
mmalc -
On Jul 1, 2009, at 7:32 PM, Bill Cheeseman wrote:> NSButton does conform to the NSValidatedUserInterfaceItem protocol,
> as its header file confirms
According to the header file and documentation I'm looking at,
NSButton conforms to the *other* protocol
(NSUserInterfaceValidations), which is the one you implement when you
want to validate, not be validated.
Nevertheless, I think I remember being confused by that documentation
in exactly the same way, and I think it is very much worth a Radar.
I've submitted rdar://problem/7026464, in which I make the following
suggestions:
* Instead of the very general term "user interface items ", introduce
the term "*validated* user interface items", or simply "validated
items", which describes them precisely and forms a clear association
with the protocol name PSValidatedUserInterfaceItem.
* Use the terms consistently everywhere -- on the "Implementing a
Validated Item" page the term "validated objects" is used.
* To avoid confusion, make it clear that only NSMenuItem and
NSToolbarItem (or whatever the list is) are validating [sic -- d'oh]
items, though of course developers can implement others.
...I read mmalc's post before submitting the Radar (in fact I referred
to the rdar he mentioned) but it only just now registered that he
quotes a part of the docs that sort of says the thing about NSMenuItem
and NSToolbarItem. But still I think it could be clearer, and might
be worth stating in more than one place.
--Andy -
On Jul 2, 2009, at 12:02 AM, mmalc Crawford wrote:> On Jul 1, 2009, at 4:33 PM, Bill Cheeseman wrote:
>> But it doesn't work at all for user controls in general, and the
>> docs are misleading (i.e., wrong) about that.
>>
>
> although I'm not sure I'd agree with Bill that the docs are *wrong*,
> they certainly could be more helpful in making it clear what the
> limitations are, so I'd still suggest filing an enhancement request.
Read my detailed response to Keary Suska, in which I trace out the
documents. I can't see any way to avoid concluding that the document
in question is "wrong," pure and simple, and always has been.> (Hmm, or appending to '<rdar://problem/2801472> UIValidation: Need a
> bit more context', which is easily old enough to go to Summer Camp
> this year...)
I still have 9 or 10 bugs open from 2002.... -
On Jul 1, 2009, at 9:15 PM, Keary Suska wrote:>> So I think you are claiming this works because the documentation
>> says so. I'm saying the documentation is wrong because it doesn't
>> work. I would love to see a project proving me wrong. Can you show
>> me one?
>
>
> No, I am saying that it works as advertised for objects that it
> works for. NSButton is not one of them, and never has been. You seem
> to assume that all user interface items should, but they don't, and
> never have, and the documentation has never said that they did. The
> documentation is explicit:
>
> "The protocols NSUserInterfaceValidations and
> NSValidatedUserInterfaceItem provide a standard way to validate user
> interface itemsâthat is, to set their state as appropriate for the
> current application context"
>
> Validation is not a function of user interface items, it is a
> function of the protocol(s) listed. Neither NSButton, nor any of its
> parents conforms to the protocol, so none of them support validation
> of this kind. Look at NSMenuItem, and you will see that it does, and
> that your validation method will always be called.
I'm not "assuming" that it works with all user controls. The document
I quoted from says it does, explicitly and in detail, without
qualification. All I asked in my original post is whether I'm correct
in concluding that in fact buttons don't work that way. I understand
that you've all confirmed that I'm correct in my conclusion. Thanks.
I must say, though, that I enjoyed your defense of the document. You
said, in so many words, that it is true only for those user interface
items for which it is true. That captures my complaint perfectly. When
a general statement has substantial qualifications, the document
should express those qualifications. Otherwise, as in this case, it
fails to serve its purpose of educating people who aren't already in
the know.
The document not only fails to disclose the qualifications; it
affirmatively misleads by giving a detailed narrative description of
how to do it in the general case. I followed the explanation in my own
code precisely, and it simply doesn't work. In the "The Target Object"
section, the document describes how to implement user interface
validation in the case of a "controller" that implements an "action
method." It says that the controller should also implement -
validateUserInterfaceItem: in order to enable or disable a user
interface item. It says, for example, that if the method returns NO,
"the user interface item is disabled." Nothing in the document
suggests that this is limited to menu items or toolbar items; instead,
it refers repeatedly to "user interface items." It goes on to give a
code example for a subclass of NSDocument. The code sample works only
because NSDocument is written to make it work (as some other document
explains; I've forgotten which), but this document doesn't explain
that rather important qualification. NSWindowController is not written
that way, and it doesn't work, contrary to the "The Target Object"
section's assertion that it does work for "controllers" and "user
interface items" in general.
It doesn't help to refer me to the NSUserInterfaceValidations and
NSValidatedUserInterface protocol documents, because that's where I
started. They are ambiguous, and they're very short on explanation. In
fact, I turned to the User Interface Validation document precisely
because I was seeking clarification of the protocol documents. Telling
me to go back and look at the protocol documents doesn't help.
The protocol documents say, as you noted, that they "work together" to
implement user interface validation. They go on to state that "The
NSMenuItem and NSToolbar Item classes take advantage of these
protocols." Grammatically, that sentence is written as if these are
simply two examples of classes that do so; it does not state that they
are the ONLY classes that do so. And the User Interface Validation
document says that NSMenuItem is "one example."
In trying to pin down whether buttons also do so, I looked at the
NSButton Class Reference document and found that it expressly conforms
to the NSUserInterfaceValidations protocol. I don't understand why you
say it doesn't.
I did find it confusing when I read the NSMenuItem and NSToolbarItem
Class Reference documents, which say that they conform to the other
protocol, the NSValidatedUserInterface protocol. But this tends to
suggest that NSButton will work, too, since NSControl, from which
NSButton inherits, also conforms to the NSValidatedUserInterface
protocol. It doesn't say so, but Apple's documentation has a long
history of neglecting to mention all the protocols that a class
conforms to. I was able to confirm from the NSControl Class Reference
document, and you can too, that NSControl does implement the -action
and -tag methods required by the NSValidatedUserInterface protocol.
So, again, I don't understand why you say it doesn't.
Putting the protocol documents and the class reference documents
together with the User Interface Validations document leads one
directly to the conclusion that buttons work just like menu items and
toolbar items in this regard. (And they should, by the way, perhaps
with an on/off switch like NSToolbarItem's -setAutovalidates: method.)
But they don't, so the document is wrong, which was my original point.
I have understood for many years that they don't, but I hadn't
previously made a thorough effort to track down whether that was only
because I wasn't doing it right. Over the last couple of days I
finally made that effort, because the documents so clearly say it does
work. I concluded that it wasn't my fault; buttons really don't work
that way. Instead, the document is simply wrong. My original post to
the list was to seek confirmation that it doesn't work with buttons.
You've given me that confirmation, for which I thank you.
What I don't understand is why everybody is working so hard to defend
an indefensible document. I'll file a bug against the document. And
against the two protocol documents, as well. And against NSControl for
failing to state that it conforms to the NSValidatedUserInterface
protocol, as it does. And a feature request to make this work with all
user controls -- then mmalc wouldn't have to rewrite the document!
--
Bill Cheeseman
<bill...> -
On Thursday, July 02, 2009, at 03:48AM, "Bill Cheeseman" <bill...> wrote:> I'm not "assuming" that it works with all user controls. The document
> I quoted from says it does, explicitly and in detail, without
> qualification.
This is why in my Radar I suggested the "validated item" terminology to indicate there is a special class of user interface items. It seems obvious to me to follow the tradition of English terms matching Objective-C names very naturally: an NSTableView is a table view, an NSTextField is a text field, and an NSValidatedUserInterfaceItem should be a validated (user interface) item.> The protocol documents say, as you noted, that they "work together" to
> implement user interface validation. They go on to state that "The
> NSMenuItem and NSToolbar Item classes take advantage of these
> protocols." Grammatically, that sentence is written as if these are
> simply two examples of classes that do so; it does not state that they
> are the ONLY classes that do so.
And it doesn't point out that they don't *always* do so (depending on the autoenablesItems and autovalidates flags). I'm not saying that doc should repeat the details of menu enabling and toolbar validation, but I do think it would be worth adding links to the "Enabling Menu Items" and "Validating Toolbar Items" sections to provide some hint that there is a larger story. I just submitted bottom-of-the-page feedback to this effect.> In trying to pin down whether buttons also do so, I looked at the
> NSButton Class Reference document and found that it expressly conforms
> to the NSUserInterfaceValidations protocol.
This is true but irrelevant. NSUserInterfaceValidations is for the object that validates, not the one that is validated. What this means is that if you have a menu item with an NSButton as its target, the button gets to decide whether the menu item is enabled. But we don't know what logic it uses to do this, because NSButton's implementation of validateUserInterfaceItem: is not documented. I would love to hazard a guess, but one doesn't come to mind offhand.> I did find it confusing when I read the NSMenuItem and NSToolbarItem
> Class Reference documents, which say that they conform to the other
> protocol, the NSValidatedUserInterface protocol. But this tends to
> suggest that NSButton will work, too, since NSControl, from which
> NSButton inherits, also conforms to the NSValidatedUserInterface
> protocol.
Well, it implements the methods, but since NSValidatedUserInterfaceItem is a formal protocol, I would say NSButton doesn't conform to it in the sense of [NSButton conformsToProtocol:@protocol(NSValidatedUserInterfaceItem)]. I agree it's very easy to be confused, because the implementation of item validation might or might not care whether the validated item conforms formally to the protocol, and this seems a natural thing for a button to do.
Since the docs in question are relatively small, very fundamental, and IMO potentially very confusing, it seems to me this is low-hanging fruit for Apple's doc team and worth addressing sooner rather than later.
--Andy -
On Jul 2, 2009, at 1:48 AM, Bill Cheeseman wrote:> I'm not "assuming" that it works with all user controls. The
> document I quoted from says it does, explicitly and in detail,
> without qualification. All I asked in my original post is whether
> I'm correct in concluding that in fact buttons don't work that way.
> I understand that you've all confirmed that I'm correct in my
> conclusion. Thanks.
You have to confess that the docs don't say, "all user interface items
conform to the NSValidatedUserInterfaceItem protocol and therefore
support validation." That is the only true *detailed* and *explicit*
statement that would indicate such. Anything else is an inference,
although a reasonable and understandable inference, considering the
docs in isolation.
Your argument seems to make the case that the problem is precisely how
the docs are *not* explicit, and therefore allow or encourage an
incorrect inference. I agree, conditionally.> It doesn't help to refer me to the NSUserInterfaceValidations and
> NSValidatedUserInterface protocol documents, because that's where I
> started. They are ambiguous, and they're very short on explanation.
> In fact, I turned to the User Interface Validation document
> precisely because I was seeking clarification of the protocol
> documents. Telling me to go back and look at the protocol documents
> doesn't help.
Well, looking at the methods that both protocols does shed light on
their purpose, as was explained by Andy Lee.> In trying to pin down whether buttons also do so, I looked at the
> NSButton Class Reference document and found that it expressly
> conforms to the NSUserInterfaceValidations protocol. I don't
> understand why you say it doesn't.
I defer to Andy's explanation.> I did find it confusing when I read the NSMenuItem and NSToolbarItem
> Class Reference documents, which say that they conform to the other
> protocol, the NSValidatedUserInterface protocol. But this tends to
> suggest that NSButton will work, too, since NSControl, from which
> NSButton inherits, also conforms to the NSValidatedUserInterface
> protocol. It doesn't say so, but Apple's documentation has a long
> history of neglecting to mention all the protocols that a class
> conforms to. I was able to confirm from the NSControl Class
> Reference document, and you can too, that NSControl does implement
> the -action and -tag methods required by the
> NSValidatedUserInterface protocol. So, again, I don't understand why
> you say it doesn't.
It's not a matter of docs, although it would be preferable that the
docs *do* indicate every protocol. Because the two protocols in
question are formal protocols, the @interface declaration must specify
conformance. If it doesn't, then no assumption of conformance should
be made. Pure and simple. Also, protocol conformance is not
inheritable in Objective-C. Therefore, neither NSControl, nor
NSButton, conform to the NSValidatedUserInterface protocol.
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Thu, Jul 2, 2009 at 3:48 AM, Bill Cheeseman<bill...> wrote:> I did find it confusing when I read the NSMenuItem and NSToolbarItem Class
> Reference documents, which say that they conform to the other protocol, the
> NSValidatedUserInterface protocol. But this tends to suggest that NSButton
> will work, too, since NSControl, from which NSButton inherits, also conforms
> to the NSValidatedUserInterface protocol. It doesn't say so, but Apple's
> documentation has a long history of neglecting to mention all the protocols
> that a class conforms to. I was able to confirm from the NSControl Class
> Reference document, and you can too, that NSControl does implement the
> -action and -tag methods required by the NSValidatedUserInterface protocol.
> So, again, I don't understand why you say it doesn't.
Because it doesn't.
You seem to think that protocol conformance is simply a matter of
having declared the proper methods. That's not how it works. If you
check with -conformsToProtocol:, it will return NO. If you try to
assign to a pointer of type id <NSValidatedUserInterface> the compiler
will warn you.
Protocol conformance is a matter of having the declaration in the
header. Nothing else counts. Especially here, where the protocol is
obviously being used as a way to claim a particular behavior, not just
an ability to respond to certain selectors.
As proof, I submit NSObject and NSCopying. NSCopying contains a single
method, -copyWithZone:. NSObject implements this method. And yet,
NSObject does not conform to NSCopying, and if you try to copy one it
will fail.
Mike -
On Jul 2, 2009, at 12:24 PM, Keary Suska wrote:> Because the two protocols in question are formal protocols, the
> @interface declaration must specify conformance. If it doesn't, then
> no assumption of conformance should be made. Pure and simple. Also,
> protocol conformance is not inheritable in Objective-C.
1. Taking that last point first, the Objective-C 2.0 Programming
Language document says this: "A class is said to conform to a formal
protocol if it adopts the protocol or inherits from another class that
adopts it." I believe, without checking, that this was true in 1.0,
also. I take that to mean that protocol conformance is in fact
inherited. That makes sense, because a protocol is simply a promise
that certain methods are implemented, and implemented methods are
inherited by subclasses.
2. The key question for me is your first point.
The way I work around the lack of automatic validation for buttons is
this: In my window controller, I implement -validateUserInterfaceItem:
and declare that my controller conforms to the
NSUserInterfaceValidations protocol. That's exactly what NSDocument
does, as I understand it. Since user interface items are not
automatically validated, I force validation by implementing NSWindow's
-windowDidUpdate: delegate method so that it loops through all
subviews of the window calling my controller's -
validateUserInterfaceItem: protocol method. (I could use something
other than -windowDidUpdate: to trigger the protocol method if
efficiency becomes an issue, but at this point doing it every time the
window updates works just fine. I am aware that Apple is struggling
with efficiency concerns in automatic validation of toolbar items.)
Now here's my question for you: In my controller's implementation of -
validateUserInterfaceItem:, I can either limit the items that I enable/
disable by checking whether their class is NSButton (which I know
responds to -action and -setEnabled:, and I can confirm that
programmatically). Or, instead, I can limit the items by checking
whether they conform to the NSValidatedUserInterfaceItem protocol. If
I do the latter, I have to declare a subclass of NSButton and declare
that it conforms to the protocol because NSButton does not itself
declare conformance, and of course I have to set the type of my
buttons to my subclass type in Interface Builder. Either technique
works (I know because I've already done it), but testing for
compliance with the NSValidatedUserInterfaceItem protocol somehow
seems purer to me.
But then, as you point out, I am arrogating to myself the decision
whether NSButton conforms to the protocol. It clearly does, in my
view, because it inherits -action and -tag methods from NSControl, and
I know they work. Therefore I don't have to reimplement them in my
subclass of NSButton, although I am perfectly entitled under the rules
of the language to re-implement them myself if I choose to do so. If I
did re-implement them in my subclass, I would have every right to
declare that my subclass conforms to the protocol, because I own my
subclass. Implementing those two methods is all that conformance
requires. Objecting to this approach if I simply rely on inheriting
NSControl's implementations of -action and -tag seems like it's
elevating form over function. In other words, I view NSButton's
failure to declare conformance to be a bug.
Now, by my logic, NSControl also conforms, because that's where -
action and -tag are declared. But NSControl does not implement -
setEnabled:, so it wouldn't make any sense as a practical matter.
That's just another way of saying that the
NSValidatedUserInterfaceItem protocol is itself faulty, because it
does not promise that a conforming class can actually enable/disable
itself. (The problem is that different user controls that can be
enabled/disabled use methods with different signatures, such as
segmented controls. Therefore, to make my approach foolproof, I have
to check not only for an item's conformance to the protocol, but also
whether it responds to the -setEnabled: selector and any other
selector that I know enables/disables a user control I care about.)
Where would you come out on this question? From your comments, I
assume you would say I should not subclass NSButton and declare it as
conforming. Then I would have to simply check whether the class of an
item is the NSButton class. You might also insist that I should not
name my validation method -validateUserInterfaceItem:, but something
else such as -updateWindow, because I risk confusing people about what
my controller really does. In that case, I'm back where most Cocoa
applications were before Cocoa bindings were invented, declaring a
custom -updateWindow method and calling it from -windowDidUpdate or
whatever.
I would prefer to do things the NSUserInterfaceValidations way, so
that I'm ready when Apple gets around to making user interface item
validation automatic, which I really think it ought to do (with an on/
off switch). (Apple will probably say I should move on to Cocoa
Bindings and get over it.)
--
Bill Cheeseman
<bill...> -
On Thursday, July 02, 2009, at 01:52PM, "Bill Cheeseman" <bill...> wrote:> On Jul 2, 2009, at 12:24 PM, Keary Suska wrote:
>
>> Because the two protocols in question are formal protocols, the
>> @interface declaration must specify conformance. If it doesn't, then
>> no assumption of conformance should be made. Pure and simple. Also,
>> protocol conformance is not inheritable in Objective-C.
>
> 1. Taking that last point first, the Objective-C 2.0 Programming
> Language document says this: "A class is said to conform to a formal
> protocol if it adopts the protocol or inherits from another class that
> adopts it." I believe, without checking, that this was true in 1.0,
> also. I take that to mean that protocol conformance is in fact
> inherited.
You are right on this one. Besides being what one would expect (what I would expect, anyway), sending conformsToProtocol: to the subclass easily confirms it.> Now here's my question for you: In my controller's implementation of -
> validateUserInterfaceItem:, I can either limit the items that I enable/
> disable by checking whether their class is NSButton (which I know
> responds to -action and -setEnabled:, and I can confirm that
> programmatically). Or, instead, I can limit the items by checking
> whether they conform to the NSValidatedUserInterfaceItem protocol.
If I may chime in (despite the fact that the question was for Keary): as you go on to point out, this brings us right back to "What does it mean to conform?" All the evidence indicates that Cocoa sends a conformsToProtocol: message. Note that NSButton returns NO for this despite implementing the methods in question. This distinction matters because a protocol is slightly more than "a promise that certain methods are implemented" -- it's also a way of stamping a class such that you can ask at runtime, "Does class X have 'Y' stamped on it?" You could have a protocol with no methods for this very purpose. (I feel like there is a common example of this in Cocoa but I can't think of it offhand, so I might be wrong.)
To look at it another way: suppose you wanted NSButton to implement -action and -tag methods for some other reason, but *not* be validated by this mechanism. The way to do it would be precisely what Apple's done: go ahead and implement the methods, but don't "stamp" NSButton as an NSValidatedUserInterfaceItem.
Getting back to your problem -- I personally would check whether the class is NSButton. Although at first glance I would have rejected this as a kludge, it is not only the simplest solution that achieves your goals and expresses your intent, it is what you would be doing anyway by creating the NSButton subclass. Instead of having code that checks for NSButtons at runtime, you would be manually picking out the instances of NSButton in your nib.> But NSControl does not implement -
> setEnabled:
Hm, you know what, it seems odd to me that the NSValidatedUserInterfaceItem protocol doesn't include setEnabled: or some such. The doc says, "If no responder returns YES, the item is disabled." But how can the application know it *can* disable the item, much less *how*, unless the item is guaranteed to implement setEnabled:?
Bill, although I think you are clearly wrong on some technical points, I agree wholeheartedly that the docs on validation need significant improvement, and I hope anyone else who agrees will file a Radar so it isn't just you and me.
--Andy -
On Jul 2, 2009, at 14:05, Andy Lee wrote:> Hm, you know what, it seems odd to me that the
> NSValidatedUserInterfaceItem protocol doesn't include setEnabled: or
> some such. The doc says, "If no responder returns YES, the item is
> disabled." But how can the application know it *can* disable the
> item, much less *how*, unless the item is guaranteed to implement
> setEnabled:?
The answer to this is [obscurely] in the documentation:
http://developer.apple.com/documentation/Cocoa/Conceptual/UIValidation/Arti
cles/implementingValidation.html#/
/apple_ref/doc/uid/TP40006268> "Before it is displayed, a user interface item checks to see if its
> target implements validateUserInterfaceItem:. If it does, then the
> enabled status of the item is determined by the return value of the
> method. You can therefore conditionally enable or disable an item by
> implementing validateUserInterfaceItem: in the target
> object." [quote #1]
IOW, it's intended that the object conforming to
NSValidatedUserInterfaceItem should initiate its own validation by
calling validateUnserInferfaceItem. It enables or disables itself by
examining the return value, so it doesn't need an "enabled" property
that can be set externally to it.
If the above is true, then I think it pretty much clears up a lot of
the confusion generated in this thread.
However, there's more. Both of the protocol reference documents say
this:
http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Pro
tocols/NSValidatedUserInterfaceItem_Protocol/Reference/Reference.html#/
/apple_ref/doc/uid/20000467> By conforming to this protocol, your control can participate in this
> validation mechanism. To validate a control, the application calls
> validateUserInterfaceItem: for each item in the responder chain,
> starting with the first responder. If no responder returns YES, the
> item is disabled. For example, a menu item that sends the copy:
> action message would disable itself if no responder in the responder
> chain can be copied. [quote #2]
If "the application calls validateUserInterfaceItem: for each item in
the responder chain" is understood to mean that something (e.g. NSApp)
makes all the calls from a loop, then it clearly contradicts quote #1.
In fact, the answer can be deduced from:
http://developer.apple.com/documentation/Cocoa/Conceptual/UIValidation/Arti
cles/ValidatingObjects.html#/
/apple_ref/doc/uid/20000745
Menus and menu items respond to an "update" method that triggers the
validation process. Something (presumable NSApp) presumable calls
'update' for the main NSMenu, and the 'update' calls trickle down to
the NSMenuItems, which then initiate their own validation.
A similar thing presumably happens starting from a windows NSToolbar.
The example laid out in this document pretty much explains how it's
implemented, and it suggests you could add similar functionality to
other classes by adding 'update' to them via a category.
IOW, quote #2 is plain wrong -- nothing directly calls
validateUserInterfaceItem: for each item in the responder chain.
Probably, something calls 'update' for everything in the responder
chain that implements 'update', but we don't really know how that works.
I really all makes sense, I think, although you could possibly argue
that the whole validation architecture is a bit whacked, and certain
argue that the documentation is royally whacked. -
Er, sorry about all the typos in the previous post on this subject.
On Jul 2, 2009, at 16:33, Quincey Morris wrote:> Something (presumabl[y] NSApp) presumabl[y] calls 'update' for the
> main NSMenu, and the 'update' calls trickle down to the NSMenuItems,
> which then initiate their own validation.
>
> A similar thing presumably happens starting from a window[']s
> NSToolbar. The example laid out in this document pretty much
> explains how it's implemented, and it suggests you could add similar
> functionality to other classes by adding 'update' to them via a
> category.
On further reflection, neither of these statements can be exactly true.
We know that not every menu is validated all the time, so either the
initiator of the validation process (NSApp? we don't know) filters out
menus and menu items that don't currently need validating, or 'update'
figures it out on a case-by-case basis.
Neither NSToolbar nor NSToolbarItem has an 'update' method, but they
have 'validateVisibleItems' and 'validate' respectively, which seem to
perform much the same role. It's curious that the strategy that the
documentation explains (as an example) for automatic toolbar item
validation *isn't* what toolbars actually use.
It remains totally mysterious what's going to cause individual
validatable interface items to trigger their own validation. Perhaps
there's no automatic general mechanism at all, and each interface item
class has to solve the problem for itself. Or, the documentation could
be construed to imply, any object in the responder chain that
implements 'update' will be have its 'update' called automatically
(when?), but that's more speculation than anything else. -
On Thursday, July 02, 2009, at 07:33PM, "Quincey Morris" <quinceymorris...> wrote:> I really all makes sense, I think,
I think it makes the most sense if you figure out the validateMenuItem: mechanism, then figure out the validateToolbarItem: mechanism, then see they're closely related (no surprise, since menus and toolbars are supposed to echo each other), then come across validateUserInterfaceItem: as an attempt at a Unifying Theory as well as a fallback.> although you could possibly argue
> that the whole validation architecture is a bit whacked, and certain
> argue that the documentation is royally whacked.
I remain optimistic that a cleaner, less confusing narrative can be told around validation.
On Thursday, July 02, 2009, at 08:38PM, "Quincey Morris" <quinceymorris...> wrote:> We know that not every menu is validated all the time,
I think menus are validated (assuming autoenablesItems) when they are pulled down. I forget where I get this from.
Toolbars are trickier, because they're visible all the time. I think someone else referred to performance issues because this means toolbars have to be checked more often.
--Andy -
On Jul 2, 2009, at 8:38 PM, Quincey Morris wrote:> It remains totally mysterious what's going to cause individual
> validatable interface items to trigger their own validation. Perhaps
> there's no automatic general mechanism at all, and each interface
> item class has to solve the problem for itself
I would summarize it like this:
In the case of menu items and toolbar items, you have to implement -
validateMenuItem: or -validateToolbarItem:, or their fallback -
validateUserInterfaceItem:, yourself. In your implementation, you
decide which items require validation by testing which action the
current item sends (or, rarely, what tag it has). If you implement one
of these -validate... methods, it is called automatically by the -
update or -validateVisibleItems mechanisms you described.
In the case of buttons, you likewise have to implement -
validateUserInterfaceItem: yourself. But that isn't enough, because
Cocoa does not call it automatically just because you implemented it.
A generic solution is to implement the -windowDidUpdate: delegate
method in your window controller, and in it loop through all the
subviews in your window's contentView. In each iteration of the loop,
call your -validateUserInterfaceItem: method, testing first to make
sure the item implements -action and -tag and -setEnabled: (or just
test whether it's a button, since all buttons do). If efficiency
becomes a problem, take steps to reduce the frequency with which -
validatedUserInterfaceItem: is called (every time the window updates
-- that is, once every time through the run loop -- may be overkill
for many validation scenarios).
--
Bill Cheeseman
<bill...> -
On Jul 3, 2009, at 01:20, Bill Cheeseman wrote:> In the case of buttons, you likewise have to implement -
> validateUserInterfaceItem: yourself. But that isn't enough, because
> Cocoa does not call it automatically just because you implemented
> it. A generic solution is to implement the -windowDidUpdate:
> delegate method in your window controller, and in it loop through
> all the subviews in your window's contentView. In each iteration of
> the loop, call your -validateUserInterfaceItem: method, testing
> first to make sure the item implements -action and -tag and -
> setEnabled: (or just test whether it's a button, since all buttons
> do). If efficiency becomes a problem, take steps to reduce the
> frequency with which -validatedUserInterfaceItem: is called (every
> time the window updates -- that is, once every time through the run
> loop -- may be overkill for many validation scenarios).
You should test for the specific view classes you want to have
validated (just NSButton, I think, but I may have missed something
from earlier in the thread). Don't try to initiate validation on every
item (even if it implements action, tag and setEnabled), because you
don't know for sure what other classes may already have validation
systems in place (like menus and toolbars do, though they of course
won't be found among the subviews).
I would also check that the button *doesn't* conform to
NSValidatedUserInterfaceItem, because if it does that certainly means
it is already participating in a validation system being initiated
elsewhere. There don't appear to be any such systems (apart from menus
and toolbars) in the Cocoa frameworks under Leopard, but who knows
what may change in the future?
Then the only danger is that if someone else (e.g. a 3rd-party
framework) implements a validation system for NSButtons in the same ad-
hoc way you're proposing, then your two systems will conflict.
However, if that's the case, you probably won't know of it (except
that validation will occur twice as many times), and there's not much
you can do about it, so it's not worth worrying about.
When you invoke validateUserInterfaceItem:, your window controller
also needs to make sure to send the message to the button's effective
target, not to self, similar to what's described in:
http://developer.apple.com/documentation/Cocoa/Conceptual/UIValidation/Arti
cles/ValidatingObjects.html#/
/apple_ref/doc/uid/20000745
so the code will look a bit like this:> id validator = [NSApp targetForAction:[button action] to:[button
> target] from: button];
> if ((validator == nil) || ![validator respondsToSelector:[button
> action]])
> [button setEnabled:NO];
> else if ([validator
> respondsToSelector:@selector(validateUserInterfaceItem:)])
> [button setEnabled:[validator validateUserInterfaceItem: (id<
> NSValidatedUserInterfaceItem>) button]];
> else
> [button setEnabled:YES];
I agree that the frequency of the validation is a side issue, to be
dealt with if there is a problem. In general, there may also be a
problem with validation *not* getting called unless there is a window
update, if the validation result might change when there is no visible
change to the window. (I believe there's a flaw like that in the
toolbar automatic validation, but I've never been able to pin it down.) -
On Jul 2, 2009, at 11:52 AM, Bill Cheeseman wrote:> On Jul 2, 2009, at 12:24 PM, Keary Suska wrote:
>
>> Because the two protocols in question are formal protocols, the
>> @interface declaration must specify conformance. If it doesn't,
>> then no assumption of conformance should be made. Pure and simple.
>> Also, protocol conformance is not inheritable in Objective-C.
>
> 1. Taking that last point first, the Objective-C 2.0 Programming
> Language document says this: "A class is said to conform to a formal
> protocol if it adopts the protocol or inherits from another class
> that adopts it." I believe, without checking, that this was true in
> 1.0, also. I take that to mean that protocol conformance is in fact
> inherited. That makes sense, because a protocol is simply a promise
> that certain methods are implemented, and implemented methods are
> inherited by subclasses.
Yeah, I misspoke there. You are absolutely correct.> 2. The key question for me is your first point.
>
> The way I work around the lack of automatic validation for buttons
> is this: In my window controller, I implement -
> validateUserInterfaceItem: and declare that my controller conforms
> to the NSUserInterfaceValidations protocol. That's exactly what
> NSDocument does, as I understand it. Since user interface items are
> not automatically validated, I force validation by implementing
> NSWindow's -windowDidUpdate: delegate method so that it loops
> through all subviews of the window calling my controller's -
> validateUserInterfaceItem: protocol method. (I could use something
> other than -windowDidUpdate: to trigger the protocol method if
> efficiency becomes an issue, but at this point doing it every time
> the window updates works just fine. I am aware that Apple is
> struggling with efficiency concerns in automatic validation of
> toolbar items.)
Why not use bindings or KVO? They will likely be much more efficient,
easier to implement, and provide more control.> Now here's my question for you: In my controller's implementation of
> -validateUserInterfaceItem:, I can either limit the items that I
> enable/disable by checking whether their class is NSButton (which I
> know responds to -action and -setEnabled:, and I can confirm that
> programmatically). Or, instead, I can limit the items by checking
> whether they conform to the NSValidatedUserInterfaceItem protocol.
> If I do the latter, I have to declare a subclass of NSButton and
> declare that it conforms to the protocol because NSButton does not
> itself declare conformance, and of course I have to set the type of
> my buttons to my subclass type in Interface Builder. Either
> technique works (I know because I've already done it), but testing
> for compliance with the NSValidatedUserInterfaceItem protocol
> somehow seems purer to me.
The whole approach seems problematic to me. I would say that you
should use the API when you can, and work around it only when you
can't (I am full of ambiguous maxims these days!) I.e., allow menus
(includes popups) and toolbars and any other object that conforms to
NSValidatedUserInterfaceItem proper ("proper" in the Objective-C view,
as opposed to your view--this has been hashed out enough I won't
elaborate) to use their automatic validation, and use a "home grown"
solution for everything else. The latter solution also preferably
working with the API rather than around it (e.g. KVO), because you can.> Where would you come out on this question? From your comments, I
> assume you would say I should not subclass NSButton and declare it
> as conforming. Then I would have to simply check whether the class
> of an item is the NSButton class. You might also insist that I
> should not name my validation method -validateUserInterfaceItem:,
> but something else such as -updateWindow, because I risk confusing
> people about what my controller really does. In that case, I'm back
> where most Cocoa applications were before Cocoa bindings were
> invented, declaring a custom -updateWindow method and calling it
> from -windowDidUpdate or whatever.
Yes, because as others point out, we don't actually know how (more
importantly, when) validation is called, so we don't know how to
duplicate it. I doubt that declaring conformance is sufficient.> I would prefer to do things the NSUserInterfaceValidations way, so
> that I'm ready when Apple gets around to making user interface item
> validation automatic, which I really think it ought to do (with an
> on/off switch). (Apple will probably say I should move on to Cocoa
> Bindings and get over it.)
I would agree with Apple, or as a concession, say use KVO.
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jul 2, 2009, at 10:52 AM, Bill Cheeseman wrote:> Apple will probably say I should move on to Cocoa Bindings and get
> over it.
I certainly would.
-jcr


