2009-10-18 109 views
5

比方說,我有這個簽名的方法:如何使用performSelector:withObject:afterDelay:一個方法使用多個參數

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

如何獲取的UIColorBOOL在那裏以及多邊形

我是否應該將它們包裝在NSArray中並將它們拉出被調用的方法?這意味着我必須改變方法信號,對嗎?

有沒有更好的方法來做到這一點?

+0

我們應該從UIColor中假設你是iPhone手機嗎? – nall 2009-10-18 09:46:27

+0

我是。這有什麼區別嗎? – willc2 2009-10-18 09:53:17

+1

是的 - 如果你在雪豹,你可以使用塊來解決這個問題。 – bbum 2009-10-18 17:05:52

回答

7

幾周前我回答了一個相當類似的問題。爲這個問題編輯下面的答案。

一般而言,我避免NSInvocation這類工作。這往往是一個維護頭痛,尤其是在未來造成重構困難。

首先,鑑於此方法:

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

它一般會被宣佈爲:

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

這一點更加緊密地遵循命名約定。

現在,我要做的是將參數捕獲到一個簡單的類中,該類提供了-invoke方法。

一些與這樣的接口:

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 

用法是直截了當的。只需創建一個PolygonPlotter實例並告訴它在延遲之後或在主線程或其他任何地方執行選擇器plot

鑑於這個問題,我懷疑你在繪圖時可能需要更多的上下文嗎?如果是這樣,你可以傳遞信息,比方說一個參數-plot,宣告方法:

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

或類似的東西。像我說的,稍微多一些代碼,但比NSInvocation模式更靈活和可重構。例如,你可以很容易地使PolygonPlotter可以存檔的東西。

0

我相信NSArray是一個合理的解決方案,是的,這意味着將方法簽名更改爲以NSArray *爲唯一參數。

4

喬·休伊特的Three20圖書館performSelector的一些先進的版本,你可能會發現有用的(我只張貼代碼段):

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

只需將它們添加到NSObject類別。

+0

我將如何實現afterDelay:函數? – willc2 2009-10-18 10:15:18

9

仍然不正是我所說的優雅,但不難吃不必改變整個API是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]; 

另一個最好的選擇就是創建一個調用您的原始方法的包裝方法希望使用適當的參數(可能以字典或數組的形式給出),該參數與延遲後執行所需的簽名相匹配。

+1

爲什麼參數索引從3開始而不是2(正如文檔似乎表明的那樣)? – willc2 2009-10-18 10:22:35

+0

它應該從2開始,而不是3. – 2009-10-18 14:13:42

+0

它從2開始。參數0和1被保留用於隱藏的'self'和'_cmd'參數。 – 2009-10-18 16:43:14

相關問題