我正在使用objective-c的forwardInvocation:
功能,我需要知道方法收到的参数类型。在我的例子中,我传递给它一个int
,但getArgumentTypeAtIndex:
告诉我它是一个id
。下面是一个简单的例子:
@interface Do : NSObject
+ (void) stuff:(int)x;
@end
@implementation Do
+ (NSMethodSignature *) methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature)
signature = [self methodSignatureForSelector:@selector(forwardInvocation:)];
return signature;
}
+ (void)forwardInvocation:(NSInvocation *)i
{
const char* argType = [i.methodSignature getArgumentTypeAtIndex:2];
NSLog(@"%s == %s", argType, @encode(id)); // @ == @
NSLog(@"%s == %s", argType, @encode(int)); // @ == i
}
@end
我是这样称呼它的:
[Do stuff:123];
知道为什么我没有得到id
而不是int
作为类型吗?
问题是,您实际上没有在类上有stuff:
方法,因此methodSignatureForSelector:
将返回nil
-看起来您发现了这一点,因此实现了自己的版本,但这在super
调用上失败,因此最终返回forwardInvocation:
的签名-这不是您想要的!
要解决这个问题,你要么需要将methodSignatureForSelector:
指向具有选择器的类,要么使用协议-如果一个类实现了协议,那么它将返回该协议中任何方法的签名,即使这些方法实际上不是由该类实现的。
下面是使用协议的示例:
@protocol DoProtocol
@optional
+ (void) stuff:(int)x;
@end
@interface Do : NSObject<DoProtocol>
@end
@implementation Do
+ (void)forwardInvocation:(NSInvocation *)i
{
const char* argType = [i.methodSignature getArgumentTypeAtIndex:2];
NSLog(@"%s == %s", argType, @encode(id)); // @ == @
NSLog(@"%s == %s", argType, @encode(int)); // @ == i
}
@end
@optional
避免了对未实现方法的任何编译器警告。methodSignatureForSelector:
的默认实现(来自NSObject
)将返回从协议获得的有效签名,因此将调用forwardInvocation:
。
只要你能让它通过编译器,无论你传递的参数是什么,它都会在运行时被解释成这样——你可以声明一个函数接受一个NSNumber
,但如果你传递一个UITableView
给它,它的class
仍然是一个UITableView
。