Type introspection with NSMethodSignature, deprecated NSObjCValueType?

  • I have a situation where I need to do some method introspection.

    Given an arbitrary selector, and after having verified that instances
    respond to the selector, I'd like to make sure the method signature
    matches a particular form.

    NSObjCValueType is listed as deprecated in the headers. (Documentation
    says "Used internally by NSInvocation—do not use it directly.")

    The documentation for -methodReturnType and -getArgumentTypeAtIndex:
    on NSMethodSignature says "This encoding is implementation-specific,
    so applications should use it with caution."

    Suppose I want to verify that a given method signature looks like an
    action method.

    if ([methodSignature numberOfArguments] == 3 &&
    0 == strcmp(@encode(void), [methodSignature methodReturnType]) &&
    0 == strcmp(@encode(id), [methodSignature getArgumentTypeAtIndex: 2]) {

    }

    Is testing the argument types in this manner, with @encode(), going to
    be future proof?

    Thanks,
    Jim
  • On Feb 1, 2008, at 9:25 AM, Jim Correia wrote:

    > I have a situation where I need to do some method introspection.
    >
    > Given an arbitrary selector, and after having verified that
    > instances respond to the selector, I'd like to make sure the method
    > signature matches a particular form.
    >
    > NSObjCValueType is listed as deprecated in the headers.
    > (Documentation says "Used internally by NSInvocation—do not use it
    > directly.")
    >
    > The documentation for -methodReturnType and -getArgumentTypeAtIndex:
    > on NSMethodSignature says "This encoding is implementation-specific,
    > so applications should use it with caution."
    >
    > Suppose I want to verify that a given method signature looks like an
    > action method.
    >
    > if ([methodSignature numberOfArguments] == 3 &&
    > 0 == strcmp(@encode(void), [methodSignature methodReturnType]) &&
    > 0 == strcmp(@encode(id), [methodSignature getArgumentTypeAtIndex:
    > 2]) {
    >
    > }
    >
    > Is testing the argument types in this manner, with @encode(), going
    > to be future proof?

    No, it's not even "present proof" without additional work and/or a lot
    restrictions.

    The problem is that there are some edge cases of @encode with
    structures and pointers to structures.  I've seen examples of even
    simple things like NSPoint and NSRect that produce different results
    on a compile time @encode and getting the value from the runtime (this
    gets worse for pointers to structures).  According to the
    documentation, it is suppose to be "{NSPoint=ff}", but I've seen
    "{NSPoint}" as the value returned by the runtime (it may have been for
    a pointer to an NSPoint, i.e., "^{NSPoint=ff}" vs "^{NSPoint}").

    It also doesn't help that there are things that aren't made part of
    the @encode (for example, an Altivec or SSE vector didn't use to come
    back as anything at all, though this may have changed).

    Obviously, there are cases (like a simple "return void, take an id")
    that you won't run into these issues.

    However, writing a string comparison routine that works to find
    "compatible" @encode isn't that hard (i.e., handling cases of ignoring
    structure contents).  You'll also have to decide if signed vs unsigned
    differences are "compatible" or not (since they have different
    encodings).  Also, is something that take an id compatible with
    something that is declared as, say, "(NSControl *)" (which becomes "@"
    vs "^{NSControl}" or "^{NSControl=....}")

    Glenn Andreas                      <gandreas...>
      <http://www.gandreas.com/> wicked fun!
    quadrium2 | build, mutate, evolve, animate  | images, textures,
    fractals, art
  • > Given an arbitrary selector, and after having verified that
    > instances respond to the selector, I'd like to make sure the method
    > signature matches a particular form.

    Any reason you’re doing this? As Glenn points out, this approach is
    fraught with trouble.

    If you’re verifying a plugin, there’s always the option of crashing.

    -Ben
  • On Feb 1, 2008, at 11:02 AM, glenn andreas wrote:

    > No, it's not even "present proof" without additional work and/or a
    > lot restrictions.

    Ugh...

    > The problem is that there are some edge cases of @encode with
    > structures and pointers to structures.  I've seen examples of even
    > simple things like NSPoint and NSRect that produce different results
    > on a compile time @encode and getting the value from the runtime
    > (this gets worse for pointers to structures).  According to the
    > documentation, it is suppose to be "{NSPoint=ff}", but I've seen
    > "{NSPoint}" as the value returned by the runtime (it may have been
    > for a pointer to an NSPoint, i.e., "^{NSPoint=ff}" vs "^{NSPoint}").
    >
    > It also doesn't help that there are things that aren't made part of
    > the @encode (for example, an Altivec or SSE vector didn't use to
    > come back as anything at all, though this may have changed).
    >
    > Obviously, there are cases (like a simple "return void, take an id")
    > that you won't run into these issues.

    So the case presented above, for the void return type and id argument,
    should be present and future proof?

    > However, writing a string comparison routine that works to find
    > "compatible" @encode isn't that hard (i.e., handling cases of
    > ignoring structure contents).  You'll also have to decide if signed
    > vs unsigned differences are "compatible" or not (since they have
    > different encodings).  Also, is something that take an id compatible
    > with something that is declared as, say, "(NSControl *)" (which
    > becomes "@" vs "^{NSControl}" or "^{NSControl=....}")

    In my test app, running on Leopard 32-bit (haven't tried Tiger or 64-
    bit), NSControl * and id both @encode() and come back from
    NSMethodSignature as "@".

    Was this not always the case?

    Jim
  • On Feb 1, 2008, at 11:23 AM, Benjamin Stiglitz wrote:

    >> Given an arbitrary selector, and after having verified that
    >> instances respond to the selector, I'd like to make sure the method
    >> signature matches a particular form.
    >
    > Any reason you’re doing this? As Glenn points out, this approach is
    > fraught with trouble.
    >
    > If you’re verifying a plugin, there’s always the option of crashing.

    There is a reason. :-)

    I was revisiting some old code today and noticed that I was perhaps
    forwarding too many messages.

    I have a view controller (my own class, predates NSViewController)
    which hooks into the responder chain when it is active.

    The view controller forwards action messages to the view so that it
    can get them when it isn't key.  (In this particular situation, it
    makes sense for the view to be able to zoom, for example, even if some
    other view in the window is key.)

    For forwarding the messages, I have essentially 3 options:

    1) Forward all unhandled messages from the controller to view.
    2) Forward only action messages, as determined by introspection.
    3) Forward messages only from a pre-defined list.

    Today I am doing 1, which is more forwarding than is necessary. 3 is a
    potential maintenance headache. So I was investigation options for
    implementing #2.

    Jim
  • On Feb 1, 2008, at 1:09 PM, Jim Correia wrote:
    >>> Given an arbitrary selector, and after having verified that
    >>> instances respond to the selector, I'd like to make sure the
    >>> method signature matches a particular form.
    > [...]
    > I was revisiting some old code today and noticed that I was perhaps
    > forwarding too many messages.
    >
    > I have a view controller (my own class, predates NSViewController)
    > which hooks into the responder chain when it is active.
    >
    > The view controller forwards action messages to the view so that it
    > can get them when it isn't key.  (In this particular situation, it
    > makes sense for the view to be able to zoom, for example, even if
    > some other view in the window is key.)
    >
    > For forwarding the messages, I have essentially 3 options:
    >
    > 1) Forward all unhandled messages from the controller to view.
    > 2) Forward only action messages, as determined by introspection.
    > 3) Forward messages only from a pre-defined list.
    >
    > Today I am doing 1, which is more forwarding than is necessary. 3 is
    > a potential maintenance headache. So I was investigation options for
    > implementing #2.

    So in this case, it sounds like you have a fallback position, which is
    to forward anything you don't recognize via a test for situation #2.
    But strcmp() is potentially too literal -- there are numbers and other
    crud, potentially, and depending on what OS you're running on,
    slightly different answers from those NSMethodSignature methods you
    mentioned.

    If there is a 'v' in the return type, and a '@' in the arg type
    string, somewhere, and the number of arguments is 3, then you're
    probably fairly safe.

    Chris
previous month february 2008 next month
MTWTFSS
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29    
Go to today