2010-04-26 3 views
27

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

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

ответ

74

Взгляните на документацию NSObject. В этом случае:

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

(обратите внимание, этот метод фактически перечислены в документации NSObject protocol). Поскольку -[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 этого вызова, и вы должны вернуть себя из метода инициализатора. Во всех случаях, ваши методы инициализатора Objective-C должен выглядеть следующим образом:

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

    return self; 
} 

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

-(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:.

+0

спасибо, это идет выше и выше. Я догадался, что мне может понадобиться использовать NSInvocation, но не уверен. Отличный ответ. – madmik3

+0

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

+0

Хорошая точка, ред. –

1

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

[parent performSelector:sel withObject:argument1]; 

или

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

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

+0

Обязательно определите точную подпись метода, например. NSSelectorFromFromString (methodWithArg1: arg2 :) – stephen

2

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

NSObject Protocol Reference От:

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

После того, что изменение сделано, вы можете сделать:

id arg = [NSNumber numberWithInt:10];  
[parent performSelector:sel withObject:arg]; 
1

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

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

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

11

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

-(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]; 
}