2

我有一个通用例程,它需要一些参数。就像是:

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

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

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

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

现在效果不错……但是,它需要我传递的方法来对传递的 Cell 的 ID 进行 switch/case,我想避免这种情况。

这就是为什么我想改用块,但我真的不知道如何将参数化块存储在变量中。

我正在尝试做的事情:

声明一个功能块doStuff

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

并将之前创建的块添加为回调

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

该块不能在那个时候被调用,而是存储在单元格中,并且只有在合适的时候才调用它。我将如何正确地解决这个问题?

非常感谢你。

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

4

3 回答 3

1

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

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

但这是一个相当奇怪和令人费解的设计。似乎有一种方法可以只用一个块来编写它,但是如果没有更好地了解你在做什么,就很难给出一个具体的解决方案。

于 2012-12-12T07:56:30.670 回答
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];}];
于 2012-12-12T08:10:45.923 回答
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;
}

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

Of course you need to release the Block once you're done using it (in the dealloc of the callback class), but that's a given.

I hope this little explanation will save someone some grief.

于 2012-12-12T09:58:51.867 回答