SEL executeSelector и аргументы - PullRequest
       41

SEL executeSelector и аргументы

28 голосов
/ 26 апреля 2010

Кажется, что должен быть простой способ вызвать селектор с некоторыми аргументами, когда все, что у вас есть, это объект SEL. Я не могу найти правильный синтаксис.

-(MyClass*) init: (SEL)sel owner:(NSObject*) parent
{
   int i =10;
   [parent performSelector:sel:i  ];
}

Ответы [ 5 ]

76 голосов
/ 26 апреля 2010

Ознакомьтесь с документацией NSObject. В этом случае:

[parent performSelector:sel withObject:[NSNumber numberWithInt:i]];

(обратите внимание, этот метод фактически указан в документации NSObject ). Поскольку -[NSObject performSelector:withObject:] требует аргумент объекта, вам нужно написать оболочку в классе родителя, как

-(void)myMethodForNumber:(NSNumber*)number {
    [self myMethod:[number intValue]];
}

чтобы распаковать NSNumber.

Если вы действительно хотите вызвать метод, который напрямую принимает необъектные аргументы (например, у вас нет контроля над источником вызываемого объекта и вы не хотите добавлять категорию), вы можете использовать NSInvocation:

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
[inv setSelector:sel];
[inv setTarget:parent];
[inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
[inv invoke];

Кстати, ваш метод выглядит как метод init, но не соответствует правильному шаблону инициализатора для Objective-C. Вам нужно вызвать инициализатор суперклассов, и вам нужно проверить nil результат этого вызова, и вы должны вернуть self из метода инициализатора. Во всех случаях ваши методы инициализатора Objective C должны выглядеть следующим образом:

-(id)myInitMethod {
    self = [super init];
    if(self != nil) {
      //perform initialization of self
    }

    return self;
}

Ваш метод (если это метод init) будет выглядеть так:

-(id) init: (SEL)sel owner:(NSObject*) parent
{
   self = [super init];
   if(self != nil) {
       int i = 10;
       NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[parent methodSignatureForSelector:sel]];
       [inv setSelector:sel];
       [inv setTarget:parent];
       [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
       [inv invoke];
   }

    return self;
}

Чтобы быть более стилистически Objective-C, я бы также переименовал инициализатор -(id)initWithSelector:owner:.

12 голосов
/ 02 февраля 2012

то, что сказал Барри Уорк, великолепно ... я только что изменил обсуждение для ленивых программистов

-(void)myMethodWith:(int)number andBOOL:(BOOL) someBool andStr:(NSString *)str{
    NSLog(@"%d %d %@",number,someBool,str);
}

-(void) testMethod{
    SEL sel = @selector(myMethodWith:andBOOL:andStr:);
    int i = 10;
    BOOL bol = YES;
    NSString *str = @"hey baby !";
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:sel]];
    [inv setSelector:sel];
    [inv setTarget:self];
    [inv setArgument:&i atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&bol atIndex:3];
    [inv setArgument:&str atIndex:4];
    [inv invoke];
}
3 голосов
/ 26 апреля 2010

Вы хотите использовать performSelector:withObject: Сложная задача - преобразовать int в объект NSO. Вы не можете использовать performSelector с сообщениями, которые принимают int параметров, вместо этого оно должно принимать id.

Из Ссылка на протокол NSObject :

aSelector должен идентифицировать метод, который принимает один аргумент типа id. Для методов с другими типами аргументов и возвращаемых значений используйте NSInvocation .

Как только это изменение будет сделано, вы можете сделать:

id arg = [NSNumber numberWithInt:10];    
[parent performSelector:sel withObject:arg];
1 голос
/ 26 апреля 2010

Вы можете использовать:

- (id)performSelector:(SEL)aSelector withObject:(id)anObject
- (id)performSelector:(SEL)aSelector withObject:(id)anObject  withObject:(id)anotherObject

Или, если вам нужно использовать более сложный метод, используйте NSInvocation class

1 голос
/ 26 апреля 2010

Для методов, которые принимают один или два объекта типа id в качестве аргументов, вы можете использовать:

[parent performSelector:sel withObject:argument1];

или

[parent performSelector:sel withObject:argument1 withObject:argument2];

Для методов с другими типами аргументов создайте NSInvocation, который может инкапсулировать произвольные вызовы методов.

...