如何在具有多个参数的方法上使用performSelector:withObject:afterDelay:

时间:2009-10-18 09:28:34

标签: objective-c cocoa cocoa-touch

假设我有一个带有此签名的方法:

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

如何在那里获得 UIColor BOOL 以及多边形

我应该将它们包装在 NSArray 中并将它们拉出被调用的方法吗?这意味着我必须改变方法sig,对吧?

有更优雅的方式吗?

4 个答案:

答案 0 :(得分: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 :(得分: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设置为可归档的内容。

答案 2 :(得分:4)

Joe Hewitt的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类别。

答案 3 :(得分:0)

我相信NSArray是一个合理的解决方案,是的,这意味着将方法签名更改为以NSArray *为唯一参数。