以下是我在Apple"定时器编程主题"中看到的示例代码:
NSMethodSignature *methodSignature = [self
methodSignatureForSelector:@selector(invocationMethod:)];
NSInvocation *invocation = [NSInvocation
invocationWithMethodSignature:methodSignature];
[invocation setTarget:self];
[invocation setSelector:@selector(invocationMethod:)];
NSDate *startDate = [NSDate date];
[invocation setArgument:&startDate atIndex:2];
如您所见,我们必须在invocationMethod
中指定NSMethodSignature
:一次,然后在NSInvocation
setSelector
中指定第二次。
对我来说,这似乎是多余的,苹果设计有这样的理由吗?
答案 0 :(得分:3)
选择器只是一个字符串,即方法的名称。它不包含有关参数类型或返回类型的信息。方法签名就是类型;它不包含有关方法名称的信息。他们是完全不相交的。
虽然在您的情况下,您通过使用methodSignatureForSelector:
询问目标对象来创建方法签名,但您不应该假设人们总是希望这样做。
您可以直接从类型编码的字符串构造方法签名。您可以从另一个方法的签名中获取它并将其应用于此方法。等等。根据具体的用例,可能不适合直接向对象询问方法签名,因为对象可能尚未实现该方法,并且稍后在被调用时会动态添加它。可以有多种原因可以分别指定类型和方法名称的灵活性。
答案 1 :(得分:2)
选择器被传递给两个非常不同的东西。
首先,我们有:
NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(invocationMethod:)];
这将生成一个method signature,它描述了返回值类型以及方法的参数的数量和类型。它不记得为此签名创建的选择器(相同的签名对多个选择器有效; -(void)foo:(NSString *)f;
和-(void)bar:(NSString *)b;
具有相同的签名,即使它们的选择器/名称不同)。
然后您创建实际的invocation。它需要知道返回值类型以及参数的数量和类型......所以你用NSMethodSignature
初始化它。但它还不知道它应该调用哪个对象和哪个选择器,你明确需要告诉它。这是选择器第二次通过。
您也可以在具有相同签名的调用中将选择器设置为另一个选择器,它也可以正常工作。
答案 2 :(得分:1)
方法签名允许NSInvocation知道NSInvocation可以使用的选择器的结构。创建NSInvocation后,您无法更改调用使用的选择器的结构,但是您可以更改选择器。因此,一个参数用于计算所用方法的结构,另一个是实际调用的方法。
稍后您可以更改它实际调用的方法,前提是它具有与您首先给出的方法签名相同的结构。你可以用一个conince构造函数编写一个类别:
+ (instancetype)invocationWithTarget:(id)target andSelector:(SEL)selector {
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
NSInvocation *invocation = [self invocationWithMethodSignature:methodSignature];
[invocation setTarget:target];
[invocation setSelector:selector];
return invocation;
}