2010-04-26 18 views
27

Wygląda na to, że powinien istnieć łatwy sposób wywołania selektora z pewnymi argumentami, gdy wszystko, co masz, jest obiektem SEL. Nie mogę znaleźć poprawnej składni.SEL performSelector i argumenty

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

Odpowiedz

74

Zapoznaj się z dokumentacją NSObject. W tym przypadku:

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

(Uwaga ta metoda jest faktycznie wymienione w dokumentacji NSObject protocol). Od -[NSObject performSelector:withObject:] wymaga argumentu obiektu, trzeba będzie napisać otoki w klasie rodzica jak

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

do unbox się NSNumber.

Jeśli naprawdę chcesz wywołać metodę, która pobiera argumentów non-object bezpośrednio (na przykład, nie masz kontroli źródła odbierającego i nie chcą, aby dodać kategorię), można użyć 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]; 

Na marginesie, twoja metoda wygląda jak metoda init, ale nie jest zgodna z prawidłowym wzorcem inicjalizacyjnym dla Objective-C. Musisz wywołać inicjator super-klas i musisz przetestować pod kątem wyniku nil z tego połączenia i musisz zwrócić ja z metody inicjalizującej. We wszystkich przypadkach, swoje metody initializer Objective-C powinna wyglądać następująco:

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

    return self; 
} 

metodę (jeśli jest to metoda startowych) będzie wtedy wyglądać tak:

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

Aby być bardziej Objective-C stylistycznie, Zmieniłbym również nazwę inicjatora -(id)initWithSelector:owner:.

+0

dzięki, to wychodzi poza nie. Zgadłem, że mogę potrzebować użyć NSInvocation, ale nie byłem pewien. Świetna odpowiedź. – madmik3

+0

Odkładając na bok, nawet jeśli nie masz kontroli nad uczestnikiem, możesz nadal napisać metodę wrapper, używając kategorii z tej klasy, aby rozpakować obiekt do typu pierwotnego. –

+0

Dobra uwaga, wyd. –

1

Dla metod, które mają jeden lub dwa obiekty typu id jako argumentów można użyć:

[parent performSelector:sel withObject:argument1]; 

lub

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

przypadku metod z innymi typami argumentów utwórz NSInvocation która może zawierać dowolne wywołania metod.

+0

Koniecznie wymień dokładny podpis metody np. NSSelectorFromFromString (methodWithArg1: arg2 :) – stephen

2

Chcesz użyć performSelector:withObject: Trudną częścią jest przekształcenie int w obiekt NSObject. Nie można używać performSelector z komunikatami, które pobierają parametry, ale muszą przyjmować id.

Z NSObject Protocol Reference:

aSelector powinien określać metodę, która pobiera jeden argument typu id. W przypadku metod z innymi typami argumentów i zwracanymi wartościami użyj NSInvocation.

Raz, że zmiana jest wykonana, można zrobić:

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

Można użyć:

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

Lub jeśli trzeba użyć bardziej skomplikowane użyć metody NSInvocation klasę

11

to, co powiedział Barry Wark, jest świetne. Właśnie zmodyfikowałem dyskusję dla leniwych programistów

-(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]; 
} 
Powiązane problemy