2009-10-18 113 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

相关问题