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 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"
    >
    The documentation does state that, and the reference for
    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