2009-10-18 19 views
5

Powiedzmy mam metoda z tego podpisu:Jak korzystać performSelector: withObject: afterDelay: na metodzie z wieloma argumentami

-(void)plotPoly:(Polygon *)poly WithColor:(UIColor *)color AndFill:(BOOL)filled; 

Jak mogę dostać że UIColor i BOOL tam jako a także Polygon?

Czy powinienem je opakować w NSArray i wyciągnąć je wewnątrz wywoływanej metody? To oznaczałoby, że muszę zmienić metodę sig, prawda?

Czy istnieje bardziej elegancki sposób na zrobienie tego?

+0

Czy powinniśmy założyć z UIColor, że jesteś na iPhone'ie? – nall

+0

Jestem. Czy to robi różnicę? – willc2

+1

Tak - jeśli byłeś na Snow Leopard, możesz użyć Bloku, aby rozwiązać ten problem. – bbum

Odpowiedz

7

Odpowiedziałem na dość podobne pytanie kilka tygodni temu. Odpowiedz poniżej, edytuj dla tego pytania.

Generalnie unikam tego rodzaju pracy pod numerem NSInvocation. Zwykle jest to ból głowy związany z utrzymaniem, aw szczególności stwarza trudności w refaktoryzacji w przyszłości.

Po pierwsze, biorąc pod uwagę ten sposób:

-(void)plotPoly:(Polygon *)poly WithColor:(UIColor *)color AndFill:(BOOL)filled; 

Byłoby ogólnie być zadeklarowane jako:

-(void)plotPoly:(Polygon *)aPoly color:(UIColor *)aColor filled:(BOOL)filledFlag; 

Wynika to konwencje nazewnictwa nieco bliżej.

Teraz zrobię to, przechwytując argumenty do prostej klasy, która zapewnia metodę -invoke.

Coś z interfejsem takich jak to:

PolyPlotter.h:

@interface PolyPlotter : NSObject 
{ 
    Polygon *poly; 
    UIColor *color; 
    BOOL filled; 
} 

+ plotterWithPoly: (Polygon *) aPoly color: (UIColor *) aColor filled: (BOOL) filledFlag; 

- (void) plot; 
@end 

PolyPlotter.m:

@interface PolyPlotter() 
@property Polygon *poly; 
@property UIColor *color; 
@property BOOL filled; 
@end 

@implementation PolyPlotter 
@synthesize poly, color, filled; 

+ plotterWithPoly: (Polygon *) aPoly color: (UIColor *) aColor filled: (BOOL) filledFlag; 
{ 
    PolyPlotter *polygonPlotter = [PolyPlotter new]; 
    polygonPlotter.poly = aPoly; 
    polygonPlotter.color = aColor; 
    polygonPlotter.filled = filledFlag; 
    return [polygonPlotter autorelease]; 
} 

- (void) plot; 
{ 
    // ... do your plotting here ... 
} 
@end 

Użycie jest bardzo proste. Po prostu stwórz instancję PolygonPlotter i powiedz jej, aby wykonał selektor po opóźnieniu lub w wątku głównym, lub cokolwiek innego.

Podejrzewam, że w momencie rysowania może być potrzebny nieco więcej kontekstu? Jeśli tak, można przekazać te informacje jako argument do -plot przez, powiedzmy, deklarując metody jak:

- (void) plot: (UIView *) aViewToPlotIn; 

czy coś takiego.

Tak jak powiedziałem, nieco więcej kodu, ale o wiele bardziej elastycznego i refaktoryzującego niż wzór NSInvocation. Na przykład możesz całkiem łatwo zrobić z PolygonPlotter coś, co można zarchiwizować.

0

Uważam, że NSArray jest rozsądnym rozwiązaniem, a to oznaczałoby zmianę podpisu metody na przyjęcie NSArray * jako jedynego argumentu.

4

Three20 biblioteka Joe Hewitt ma jakieś zaawansowane wersje performSelector, które mogą okazać się przydatne (ja tylko umieścić fragment):

- (id)performSelector:(SEL)selector withObject:(id)p1 withObject:(id)p2 withObject:(id)p3 { 
    NSMethodSignature *sig = [self methodSignatureForSelector:selector]; 
    if (sig) { 
    NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig]; 
    [invo setTarget:self]; 
    [invo setSelector:selector]; 
    [invo setArgument:&p1 atIndex:2]; 
    [invo setArgument:&p2 atIndex:3]; 
    [invo setArgument:&p3 atIndex:4]; 
    [invo invoke]; 
    if (sig.methodReturnLength) { 
     id anObject; 
     [invo getReturnValue:&anObject]; 
     return anObject; 
    } else { 
     return nil; 
    } 
    } else { 
    return nil; 
    } 
} 

Wystarczy dodać je do kategorii NSObject.

+0

Jak mogę zaimplementować funkcję AfterDelay:? – willc2

9

Nadal nie dokładnie to, co nazwałbym elegancki, ale mniej fuj niż konieczności zmiany całego API jest NSInvocation:

Polygon *poly; 
UIColor *color; 
BOOL filled; 
// Assume the above variables exist 
NSInvocation *inv = [NSInvocation invocationWithMessageSignature:[target messageSignatureForSelector:message]]; 
[inv setArgument:&poly atIndex:2]; 
[inv setArgument:&color atIndex:3]; 
[inv setArgument:&filled atIndex:4]; 
[inv performSelector:@selector(invokeWithTarget:) withObject:target afterDelay:1]; 

Drugim najlepszym rozwiązaniem jest po prostu utworzyć metodę otoki, który wywołuje oryginalną metodę chcę z odpowiednimi argumentami (być może podanymi jako słownik lub tablica), które pasują do podpisu potrzebnego do wykonania po opóźnieniu.

+1

Dlaczego indeks argumentu zaczyna się od 3, a nie 2 (jak zdają się wskazywać dokumenty)? – willc2

+0

Powinien zaczynać się od 2, nie 3. –

+0

Rozpoczyna się od 2. Argumenty 0 i 1 są zarezerwowane dla ukrytych parametrów 'self' i' _cmd'. –

Powiązane problemy