Objective-C - 有没有办法在另一个对象上使用任何类(UIView)作为协议?

时间:2014-07-31 06:25:20

标签: objective-c objective-c-runtime

我一直在使用一些相当奇特的概念在Objective-C中进行实验。

以下是一个例子: 基本上我有一个名为“theFilter”的对象应该从另一个对象“theSender”获取所有消息和“Some_More_Messages”。过滤器实例旨在对任意数量的实例进行过滤,所有实例都是不同的类。根据某些标准,它将“Some_More_Messages”协议中的消息发送给其他对象,而其他所有对象只采用标准路径。

Filter<Some_More_Messages> *theFilter;

例如,我希望在UIView实例前面有这个过滤器实例,我需要我的“Filter”对象才能接收UIView实现的所有消息。类似的东西:

Filter<UIView,Some_More_Messages> *theFilter;

但我无法继续为我需要的每个类创建协议。这是为了让编译器停止抱怨并获得自动完成和其他所有内容。

有什么想法吗?

PS。在“theSender”的代码中,我从不直接引用UIView实例,而是与其“filterInstance”对话并发送它“Some_More_Messages”,而不是UIView实例知道的。它知道它执行的东西,所有其他选择器被重定向到其他一些实例。

2 个答案:

答案 0 :(得分:2)

您可以实施forwardingTargetForSelector:

@interface Filter : NSObject /*NSProxy*/ <FilterProtocol>

@property UIView *view;

+ (UIView<FilterProtocol> *)filterWithView:(UIView *)view;

@end

@implementation

+ (UIView<FilterProtocol> *)filterWithView:(UIView *)view {
    return (UIView<FilterProtocol> *)[[self alloc] initWithView:view];
}

- (id)initWithView:(UIView *)view {
    self = [super init];
    if (self) {
        self.view = view;
    }
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([self.view respondsToSelector:aSelector]) {
        return self.view;
    }

    return [super forwardingTargetForSelector:aSelector];
}

- (void)someFilterProtocolMethod {}

@end

 UIView<FilterProtocol> *filteredView = [Filter filterWithView:view];
 [filteredView addSubview:otherView]; // call addSubview on view
 [filteredView someFilterProtocolMethod]; // call someFilterProtocolMethod on filter object

答案 1 :(得分:0)

更新:这是一个好主意,但实施不当,请检查Bryan Cheng's answer是否正确实施。


我认为您正在尝试实现多重继承。虽然Objective-C不支持,但您可以通过设置UIView实例并将未处理的消息转发给它来模仿它。

您必须将NSInvocations转发到UIView,如下所示:

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([self respondsToSelector:[anInvocation selector]]) {
        // Try to use our version of the selector
        [super forwardInvocation:anInvocation];
    } else {
        // But if we don't have that method, delegate it to the UIView
        [anInvocation invokeWithTarget:self.view];
    }
}

您还可以通过覆盖respondsToSelector:isKindOfClass:和其他一些方法来欺骗其他对象,使其看起来像您实际上是UIView。在Runtime Programming Guide

中阅读有关此高级技术的更多信息 顺便说一下,如果您不想让它崩溃,但不需要将邮件实际转发到内部UIView,那么让respondsToSelector:方法返回YES如果它是UIView方法,但不要对forwardInvocation:位执行任何操作。