2013-06-04 3 views
0

Я использую функцию объектива-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 как тип?

ответ

3

Проблема заключается в том, что у вас нет на самом деле имеют 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:.

+0

Это работает, но в моем случае мне нужен протокол, который будет добавлен с категорией, а не в оригинальной декларации '@ interface'. По какой-то причине это не работает. – bendytree

+0

Я закончил тем, что вытащил подпись непосредственно из протокола: '[NSMethodSignature signatureWithObjCTypes: protocol_getMethodDescription (@protocol (...), selector, 0, 0) .types]' – bendytree

0

Пока вы можете получить его мимо компилятором, что бы вы ни передать в качестве аргумента будет интерпретироваться как таковой во время выполнения - вы могли бы объявить, что функция принимает NSNumber, но вы передаете UITableView к нему, это class все равно будет UITableView.

 Смежные вопросы

  • Нет связанных вопросов^_^