Re: Surrogate object / forwarding
Re: Surrogate object / forwarding
- Subject: Re: Surrogate object / forwarding
- From: "Sven A. Schmidt" <email@hidden>
- Date: Thu, 3 Jan 2002 18:06:35 +0100
Ondra,
thanks for your reply.
On Donnerstag, Januar 3, 2002, at 04:07 Uhr, Ondra Cada wrote:
SAS> 1. I get compiler warnings that my class doesn't respond to the
SAS> forwarded messages (they are actually forwarded at runtime). Is
there a
SAS> way to tell the compiler that this isn't true?
Yep. Make your class an NSMutableDictionary subclass.
That's exactly what I want to avoid by forwarding. I can't subclass
without providing all kinds of methods, because NSMutableDictionary is
in a class cluster. If I provide all kinds of methods, I might just as
well implement them in my current approach - which I chose because I
thought it to be elegant to use forwarding (read: I was hoping to get
away without too much typing :-).
SAS> it responds to them. Is it because they're not public?
Nope, there is nothing like "public" or "non-public" method in ObjC.
Ah, of course. I was confusing that with the ivar visibility.
Actually, I am surprised too. This should _not_ work, *IF* I understand
you
properly and you mean that
if ([myObject respondsToSelector:@selector(setMin:)]) NSLog(@"Bingo!");
writes out Bingo indeed.
OTOH, if you just meant that
[myObject setMin:...]
works, then the answer's plain: the message sending does not use
respondsToSelector internally. The apropriate method is just found in
the
class structure and called. If it is there, it gets called all right,
even if
"respondsToSelector:" would return NO.
I meant the latter and was assuming that every selector had to meet that
requirement. For example if an object isn't statically typed, I'd have
expected the runtime to find out about the selector via
"respondsToSelector:".
Thinking about it, with the way I implemented "respondsToSelector:"
(returning super's || [self dictionary]'s reponse) I'm selling my object
for less than it actually is. If, for some reason I'd want another
object to forward to it, it wouldn't answer to messages it actually
knows.
As I've just now found out, implementing
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ( [ self respondsToSelector: aSelector ] ) {
return [ self methodSignatureForSelector: aSelector ];
} else {
return [[ self task ] methodSignatureForSelector: aSelector ];
}
}
along with the "forwardInvocation:" is all that's required to have
transparent forwarding (note I changed "super" to "self" and removed the
custom "respondsToSelector:"). That should avoid the above problem. (Not
the compiler warnings, though.)
SAS> 3. The NSObject class description has the following to say about
SAS> instancesRespondToSelector:
SAS>
SAS> "+ (BOOL)instancesRespondToSelector:(SEL)aSelector
SAS> Returns YES if instances of the class are capable of responding to
SAS> aSelector messages, NO otherwise. To ask the class whether it,
rather
SAS> than its instances, can respond to a particular message, send the
SAS> respondsToSelector: NSObject protocol instance method to the class
SAS> instead."
SAS>
SAS> Now, why would I use a class method to find out about instance
SAS> responders, while the instance method respondsToSelector: (from its
SAS> description) seems to handle class and instance methods alike? I
this a
SAS> doc error, i.e. should instancesRespondToSelector: inform about
class
SAS> methods, not instance methods?
Uh-oh.
(i) respondsToSelector: works on the object which receives the message.
In
other words, if sent to an instance, it "searches" - methods, if sent
to a
class, it "searches" + methods.
Therefore, if you re-implement -respondsToSelector:, you change the way
how
an instance looks to the world; if you re-implement
+respondsToSelector:, you
change the way how a class looks to the world.
(ii) instancesRespondToSelector: is a class method, which allows you to
check which selectors _instances_ respond to even if you have none. Like
if ([SomeClass instancesRespondToSelector:someSel]) ...
which is quite convenient in case you just happen to have no SomeClass
instance, and don't want to perform the superfluous allocation of
if ([[[[[SomeClass alloc] init] autorelease]
respondsToSelector:someSel]) ...
which can for some classes be pretty expensive, and what's worse, is not
quite right if used for an unknown class (since "init" might not be the
proper initializer for it).
Yes, I was aware of the meaning (sort of). I should have explained
better. The way I understand the sentence
"To ask the class whether it, rather than its instances, can
respond to a particular message,
send the respondsToSelector: NSObject protocol instance method to
the class instead."
in "instancesRespondToSelector:" is the following:
"If you want to now about how the class looks to the world, ask the
_instance_ if it responds to selector"
Re-reading this for the zillionth time now, I just noticed the ending in
"instance method to the _class_ instead". I guess, I was (am) confusing
a couple of things here. It seems that since "respondsToSelector:" is
from the NSObject protocol, and since NSObject conforms to it, the class
can receive the instance method. (Or is it the fact that class objects
can receive instance methods of the root object as stated on p. 102 of
the ObjC book?) Am I making any sense at all?
Maybe I should heed the warning on p. 152 of that same book which more
or less says about forwarding: this is advanced stuff - you better know
what you're doing when you're doing it (which is pretty good general
advice). Maybe I'll subclass after all... I could be deep in the next
problem by the time I've read and written all this... :-)
Thanks again,
Sven