Reputation: 3573
UIView
I have a subclass MyView
of UIView
.
This subclass has a @property UIView * realView
.
Whenever a message is sent to MyView
, I want to "forward it" to self.realView
, excepted for few messages.
For instance, in the implementation of MyView
, I would have this override:
- (void)setBackgroundColor:(UIColor *)color
{
[self.realView setBackgroundColor:color] ;
}
Instead of overriding explicitly all the methods, can I do it automatically, at the runtime?
For some methods, I want to have an explicit control. For instance:
- (void)setFrame:(CGRect)frame
{
/* do stuff */
[super setFrame:frame] ;
}
Upvotes: 3
Views: 1115
Reputation: 5298
It's entirely possible. First you need WZProtocolIntercepter. Then use the intercepter as the normal UIView:
WZProtocolInterceptor* fakeView = [[WZProtocolInterceptor alloc]
initWithInterceptedProtocol:@protocol(TheMethodsForTheMiddleManToHandle)];
fakeView.receiver = self.realView;
fakeView.middleMan = self;
[someViewController.view addSubview:fakeView];
Put the methods you want to control in TheMethodsForTheMiddleManToHandle
:
@protocol TheMethodsForTheMiddleManToHandle
- (void)setFrame:(CGRect)frame;
@end
Upvotes: 0
Reputation: 125007
Instead of overriding explicitly all the methods, can I do it automatically, at the runtime?
You implement the -forwardInvocation:
method to send any unrecognized messages to the other object. -forwardInvocation
is called whenever an object doesn't implement the selector that's passed to it as a sort of second chance to handle a message. You can override it to send the message to another object (which is pretty much what NSProxy does), log the messages, etc.
As @cobbal points out below, -forwardInvocation
will help you with methods not implemented in your superview, but it won't handle methods that are implemented int the superview because your MyView
inherits implementations of those. For example, if you want to use a UIView
as a proxy for a UIButton
, all the methods specific to UIButton
can be handled by -forwardInvocation:
, but those defined by UIView
cannot. In order to get a behavior other than the inherited method, you will of course need to override. In some situations you can get around that by deriving MyView
from NSObject
or UIResponder
instead of from UIView
, thus avoiding the inherited UIView
implementations, but if MyView
needs to be a real view you're stuck with overriding each method.
If you think about it, it's hard to imagine how your goal could be met without explicitly overriding each inherited method. You say that you only want to forward most messages, but how can the poor runtime tell which ones you do want to forward and which ones you don't? All it can do is look for a method for the given selector and call it if it finds one, or take some action (like calling -forwardInvocation:
) if it doesn't.
Update: @robmayoff points out -forwardingTargetForSelector:
, which didn't occur to me but is probably a better solution in your case. It still doesn't handle the situation where you need to redirect methods that you inherit from a superclass, though.
Upvotes: 4