Ожидайте, что тип аргумента будет целым, но вместо этого получите идентификатор

Я использую forwardInvocation: особенность target-c и мне нужно знать, какой тип аргумента получил метод. В моем примере я передаю это 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 как тип?

2 ответа

Решение

Проблема в том, что у вас нет 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,

Другие вопросы по тегам