【问题标题】:How to use performSelector:withObject:afterDelay: on a method with multiple arguments如何在具有多个参数的方法上使用 performSelector:withObject:afterDelay:
【发布时间】:2009-10-18 09:28:33
【问题描述】:

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

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

如何在其中获得 UIColorBOOL 以及 Polygon

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

有更优雅的方法吗?

【问题讨论】:

  • 我们是否应该根据 UIColor 假设您在 iPhone 上?
  • 我是。这有什么不同吗?
  • 是的——如果你在 Snow Leopard 上,你可以使用 Block 来解决这个问题。
  • 我使用 NSArray 策略。在我正在做的一些动画中,回调需要六个不同的 int 值来知道如何完成动画并继续。 (UIView 的 setAnimationDidStopSelector: 也只允许一个对象出现......) 将它们打包为 1 行代码到 NSArray 中,6 行代码在回调中解包。非常容易理解的代码,虽然不太可能给任何人留下深刻印象。

标签: objective-c cocoa cocoa-touch


【解决方案1】:

仍然不完全是我所说的优雅,但比必须更改整个 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];

另一个最佳选择是创建一个包装器方法,该方法使用适当的参数(可能作为字典或数组给出)调用您想要的原始方法,该方法与延迟后执行所需的签名相匹配。

【讨论】:

  • 为什么参数索引从 3 而不是 2 开始(如文档所示)?
  • 从 2 开始。参数 0 和 1 保留给隐藏的 self_cmd 参数。
  • 很抱歉。输入第一个,然后为下一个增加。
  • 您的意思是“invocationWithMethodSignature”吗?这种方法仍然对我不起作用。
  • 这个 NSInvocation 对象的生命周期会发生什么?如果您在延迟后执行选择器,则在当前运行循环结束时,此 NSInvocation 对象应该自动释放,因此不会出现延迟。如果从一个本身不会很长的对象(即模态视图控制器在下一个运行循环中调用委托)调用它,那么您不能将 NSInvocation 存储在调用对象中。
【解决方案2】:

几周前我回答了一个非常相似的问题。为这个问题编辑了下面的答案。

一般来说,我会避免 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 制作成可以存档的东西。

【讨论】:

    【解决方案3】:

    Joe Hewitt 的 Three20 库有一些您可能会觉得有用的高级版 performSelector(我只发布了一个 sn-p):

    - (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 的类别中即可。

    【讨论】:

    • 如何实现 afterDelay: 函数?
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 2022-10-16
      • 1970-01-01
      • 1970-01-01
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多