我创建了一个包装 UITextView 并添加一些 ui 元素的类。我希望新类的 API 与 UITextView 相同,因此我使用消息转发(如下所列)在包装文本 View 和委托(delegate)之间中继消息。

令人恼火的是,编译器对我的转发类实例的方法调用发出警告。例如,以下行将生成错误:

[aMyTextView setContentOffset:CGPointZero animated:YES];

所以我被迫为这些方法声明和创建“手动转发”实现,这违背了使用消息转发的全部目的。
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
    [_textView setContentOffset:contentOffset animated:animated];
}

我知道解决这个问题的通常方法是使用 performSelector: 方法之一,但这是 a) 当某些参数不是 NSObjects 时很麻烦(尽管 Erica Sadun's extensions 有很大帮助),b) 再次,完全违背了创建的意图一个透明的包装。

(子类化 UITextView 也是不可能的,因为我需要在文本 View 下方插入 View 。)

有没有办法解决这个问题?

类的所有相关部分的列表:
@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

最佳答案

声明一个类别,该类别提供您要转发的方法的方法声明:

@interface MyTextField (ImGonnaLetYouFinishButFirstImForwardingThese)
... methods you want to forward here ...
@end

无需提供@implementation。

请注意,这是一个相当不典型的模式。不公平,非常。你应该没有理由不能子类化。你说子类化 UITextView 也是不可能的,因为我需要在文本 View 下方插入 View ,但事实并非如此。



如果你需要一个组,创建一个 UIView 子类来适本地管理各种 subview ,不需要转发。然后您可以随意订购 View 。

转发很少使用。沿着这条路走下去的是疯狂。听起来您的设计确实有点杂草丛生,但没有足够的信息来真正说出更具体的内容。

关于objective-c - 在进行消息转发时避免编译器警告,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2259012/

10-15 05:47