我一直在使用一些相当奇特的概念在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实例知道的。它知道它执行的东西,所有其他选择器被重定向到其他一些实例。
答案 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:
位执行任何操作。