Objective-C - 存储带有回调参数的块

时间:2012-12-12 07:47:48

标签: objective-c ios callback

我有一个常规例程,它需要一些参数。 类似的东西:

-(id) doStuff:(int)A:(int)B:(int)C {
    //doStuff
    return object;
}

我有一个UITableViewController,其中包含许多自定义单元格,每个单元格都有自己的ID。当“保存”被点击时,这些单元格被迭代,并且一些单元格在被保存时需要“附加行为”。

到目前为止,我已经创建了一个'Callback'对象,它在自定义单元格中存储了NSString *和一个委托。在“保存”后,单元格会查看是否有要应用的回调并使用

SEL sel = NSSelectorFromString(Sel);
if([Del respondsToSelector:sel])
    [Del performSelector:sel withObject:Cell];

现在效果不错......但是,它需要我传递的方法对传递的Cell的ID进行切换/大小写,我想避免这种情况。

这就是我想使用块的原因,但我真的不知道如何在变量中存储参数化块。

我正在尝试做什么:

声明一个功能块doStuff

id (^doStuff) (int, int, int) = ^(int A, int B, int C) {
    //does Stuff
};

将先前创建的块添加为回调

[Cell addCallback:(^doStuff)(1, 2, 3)];

此时不得调用该块,而是将其存储在单元格中,并在时间合适时调用它。 我该如何正确地解决这个问题?

非常感谢。

编辑:我还想避免的是将块中的参数存储在单元格中并在调用时传递它们,因为这将需要我不必要地进一步专门化单元格。

3 个答案:

答案 0 :(得分:1)

听起来你想要的是一个调用你的块的块,如下所示:

[cell addCallback:^{ doStuff(1, 2, 3); }];

但这是一个相当古怪和错综复杂的设计。看起来似乎只有一种方法可以用一个块来编写它,但很难给出一个特定的解决方案而不能更好地了解你正在做什么。

答案 1 :(得分:0)

最直接的方法是创建一个包含块参数外观的typedef,然后用它来声明一个新的属性/ ivar。以下示例代码是从 Sensible TableView 框架SCCellActions类中复制的:

typedef void(^SCCellAction_Block)(SCTableViewCell *cell, NSIndexPath *indexPath);

@interface SCCellActions : NSObject
...
@property (nonatomic, copy) SCCellAction_Block willDisplay;
...
@end

然后您可以按如下方式设置属性:

cellActions.willDisplay = ^(SCTableViewCell *cell, NSIndexPath *indexPath)
{
    cell.backgroundColor = [UIColor yellowColor];
};

同样,您可以按如下方式声明参数:

...
- (void)callActionBlock:(SCCellAction_Block actionBlock)
{
    if(actionBlock)
    {
        actionBlock(self.cell, self.cellIndexPath);
    }
}
...

在这种情况下,应该像这样调用该方法:

[myObject callActionBlock:^(SCTableViewCell *cell, NSIndexPath *indexPath {cell.backgroundColor = [UIColor yellowColor];}];

答案 2 :(得分:0)

这个答案是基于Chuck的建议,并描述了我遇到的陷阱。

创建:

Cell = [self CreateCell];
[Cell addCallback:^{ return doStuff(Cell, 1, 2, 3, 4) } At:ON_SAVE];

doStuff是在单元格之前声明的本地块。我无法将其直接添加到单元格中,因为我还需要对块内的调用单元格的引用。

此时的陷阱:类变量。 一个块只会保留...或者更确切地说'复制'...局部变量,而不是类变量。 假设'Cell'是一个类变量并由'CreateCell'设置,该块将在块执行时使用Cell的值。

因此,重要的是要记住声明一个局部变量,如果需要,它假定了类变量的值。

存储

- (void) addCallback:(CallBlock_t)B At:(int)at {
    //Creates a Callback-Object and passes it the block and adds it to an Array.
}

- (id) initWithBlock:(CallBlock_t)B At:(int)at {
    self = [super init];
    if(self) {
        Block = [B copy];    //Yes, Copy. Not retain.
        When = at;
    }
    return self;
}

此时陷阱:如果仅保留块,则调用函数中的本地块将超出范围,程序将因“访问不良”而失败。复制解决了这个问题。

当然你需要在使用它之后释放Block(在回调类的dealloc中),但这是给定的。

我希望这个小小的解释会让别人感到悲伤。