I created a class that wraps a UITextView and adds some ui elements. I want the new class' API to be identical with UITextView, so I use message forwarding (listing below) to relay messages between the wrapped text view and the delegate.
The irritating thing is that the compiler issues warnings for method invocations on instances of my forwarding class. For example, an error will be generated for the following line:
[aMyTextView setContentOffset:CGPointZero animated:YES];
So I am forced to declare and create "manually forwarding" implementations for these methods, which defeats the whole purpose of using message forwarding.
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
[_textView setContentOffset:contentOffset animated:animated];
}
I know the usual way of getting around this is to use one of the performSelector:
methods, but this is a) cumbersome when some arguments are not NSObjects (although Erica Sadun's extensions are a big help), b) again, completely contrary to the intention of creating a transparent wrapper.
(Subclassing UITextView is also out of the question, because I need to insert views below the text view.)
Is there a way to get around this?
Listing of all relevant parts of the class:
@interface MyTextField : UIView<UITextViewDelegate>
{
UIImageView* _border;
UITextView* _textView;
UIButton* _clearButton;
NSObject<UITextViewDelegate>* _delegate;
}
@implementation MWTextField
. . .
// Forwards messages in both directions (textView <--> delegate)
#pragma mark Message forwarding
// Protocol messages will only be sent if respondsToSelector: returns YES
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([_delegate respondsToSelector:aSelector])
return YES;
else
return [super respondsToSelector:aSelector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
// First, try to find it in the UITextView
if ([_textView respondsToSelector:selector])
{
return [_textView methodSignatureForSelector:selector];
}
// Then try the delegate
else if ([_delegate respondsToSelector:selector])
{
return [_delegate methodSignatureForSelector:selector];
}
else
{
return [super methodSignatureForSelector: selector];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
SEL aSelector = [invocation selector];
if ([_textView respondsToSelector:aSelector])
{
[invocation invokeWithTarget:_textView];
}
else if ([_delegate respondsToSelector:aSelector])
{
[invocation invokeWithTarget:_delegate];
}
else
{
[self doesNotRecognizeSelector:aSelector];
}
}
. . .
@end