我创建了一个包装UITextView并添加一些ui元素的类。我希望新类的API与UITextView相同,因此我使用消息转发(下面列出)在包装的文本视图和委托之间中继消息。
令人恼火的是,编译器会在转发类的实例上发出方法调用警告。例如,将为以下行生成错误:
[aMyTextView setContentOffset:CGPointZero animated:YES];
所以我被迫为这些方法声明并创建“手动转发”实现,这违背了使用消息转发的全部目的。
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
[_textView setContentOffset:contentOffset animated:animated];
}
我知道解决这个问题的常用方法是使用performSelector:
方法之一,但是当一些参数不是NSObjects时,这很麻烦(尽管Erica Sadun's extensions是一个很大的帮助), b)再次,完全违背了创建透明包装的意图。
(对UITextView进行子类化也是不可能的,因为我需要在文本视图下面插入视图。)
有没有办法解决这个问题?
列出该类的所有相关部分:
@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
答案 0 :(得分:4)
声明一个类别,该类别提供您要转发的方法的方法声明:
@interface MyTextField (ImGonnaLetYouFinishButFirstImForwardingThese)
... methods you want to forward here ...
@end
无需提供@implementation。
请注意,这是一种相当不典型的模式。不公平,非常。应该没有理由不能进行子类化。你说 Subclassing UITextView也是不可能的,因为我需要在文本视图下面插入视图,但事实并非如此。
如果我将UITextField子类化,我就能做到 与其他视图一起添加它们 作为子视图,这意味着他们将 在文本字段的顶部。我想我 可以修改drawRect:...那是什么 你会建议吗?或者你有什么 你的袖子在哪里?
如果您需要一个组,请创建一个UIView子类,它适当地管理各种子视图,不需要转发。然后你可以随意订购视图。
极少使用转发。沿着这条路走下去就是疯狂。听起来你的设计听起来有点杂草,但没有足够的信息可以说出更具体的信息。
答案 1 :(得分:0)
简单的解决方案是使用动态类型并将aMyTextView
声明为id
,警告将消失。