我在一个项目中遇到了这个代码,它正在使用// Public interface
@interface CCDelegateSplitter : NSObject
- (void) addDelegate: (id) delegate;
- (void) addDelegates: (NSArray*) delegates;
@end
// Private interface
@interface CCDelegateSplitter ()
@property(strong) NSMutableSet *delegates;
@end
@implementation CCDelegateSplitter
- (id) init
{
self = [super init];
_delegates = [NSMutableSet set];
return self;
}
- (void) addDelegate: (id) delegate
{
[_delegates addObject:delegate];
}
- (void) addDelegates: (NSArray*) delegates
{
[_delegates addObjectsFromArray:delegates];
}
- (void) forwardInvocation: (NSInvocation*) invocation
{
for (id delegate in _delegates) {
[invocation invokeWithTarget:delegate];
}
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *delegated = [(NSObject *)[_delegates anyObject] methodSignatureForSelector:selector];
return our ? our : delegated;
}
- (BOOL) respondsToSelector: (SEL) selector
{
return [[_delegates anyObject] respondsToSelector:selector];
}
@end
。我想知道它应该做什么,为什么我们需要它。简单的解释将不胜感激。我发布了代码。
{{1}}
答案 0 :(得分:4)
我假设您知道NSInvocation
是什么(如果不是,它是一个包含进行方法调用所需的所有信息的数据结构;想想"块&#34 ;从很久以前就把块添加到语言中了。)
forwardInvocation:
是运行时无法找到方法实现的方法之一。因此,如果您将-doSomething
消息传递给对象[object doSomething]
,它将首先检查它是否具有doSomething
方法。然后它会检查它的超类。它会尝试动态方法解析(例如resolveInstanceMethod
)。它会查找转发目标(forwardingTargetForSelector:
),最后,如果其他所有内容都失败,它将创建一个调用(使用methodSignatureForSelector:
并向{} {向{ {1}}。默认情况下,forwardInvocation:
只调用forwardInvocation:
会在iOS上崩溃你(或终止OS X上的当前线程)。但你可以覆盖它来做其他事情(就像他们在这里一样) )。
doesNotRecognizeSelector:
是必需的,以便运行时系统可以从消息中创建调用。这个要么从这个对象或它的超类返回一个方法签名,要么它的一个目标要求适当的方法签名。选择器本身并不足以弄清楚如何调用方法。系统需要向对象询问方法的实际工作方式(所需的类型和返回的类型)。
您发布的代码是一个多代表蹦床。它将接受其目标响应的任何选择器(技术上它会选择一个随机目标并查看它是否响应),并且它会将该消息转发给它的所有目标。
对于类似的蹦床和一些关于使用的评论,您可能需要查看RNObserverManager。
答案 1 :(得分:3)
看看bfitch评论中的链接。这涵盖 NSInvocation是什么,并暗示为什么你会使用它,但不会详细介绍为什么。
NSInvocation
允许您执行相当高级的操作,例如创建实际将消息转发到另一个对象的代理对象。使用NSInvocation,可以在运行时获取 ANY 消息并将其转发给另一个对象。
另一个例子是performSelector系列方法。有performSelector:
,performSelector:withObject:
和performSelector:withObject:withObject:
。 (加上performSelector:withObject:afterDelay:
,performSelector:onThread:
等变体。)这些方法将0,1或2个对象作为参数。如果你需要在另一个带有标量参数的对象上调用一个方法,或者除了0,1或2个对象之外的任何对象,你就不幸了。但是,您可以使用NSInvocation发送包含任何类型参数的消息。
请注意,当将块添加到Objective-C时,对performSelector和NSInvocation等技巧的需求会减少。块可以从其封闭范围引用变量,这使它们更加灵活。