简体   繁体   English

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

[英]Objective-C - Storing block with parameters for callback

I have a general routine, which takes a few parameters. 我有一个通用例程,它带有一些参数。 Something like: 就像是:

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

I have a UITableViewController , which houses a number of custom cells, each with their own ID. 我有一个UITableViewController ,其中包含许多自定义单元格,每个单元格都有自己的ID。 When 'Save' is hit, these cells are iterated and some cells need 'additional behaviour' when they are being saved. 当单击“保存”时,将迭代这些单元格,并且某些单元格在保存时需要“其他行为”。

Up to now, I've created a 'Callback' object, which stores an NSString * and a delegate in the custom cell. 到目前为止,我已经创建了一个“回调”对象,该对象在自定义单元格中存储了一个NSString *和一个委托。 Upon being 'Saved', the cell looks, whether it has any callbacks to apply and uses 在“保存”后,该单元格看起来是否有任何回调要应用和使用

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

Now that works somewhat well..., however, it requires the method I pass to do a switch/case on the ID of the Cell that's passed, and I'd like to avoid that. 现在效果不错...但是,它需要我传递的方法对传递的Cell的ID进行切换/处理,我想避免这种情况。

That's why I'd like to use blocks instead, but I don't really know how to store a parameterized block in a variable. 这就是为什么我想使用块代替的原因,但是我真的不知道如何在变量中存储参数化块。

What I'm trying to do: 我正在尝试做的是:

Declare a function block doStuff . 声明功能块doStuff

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

And add the previously created block as callback 并将先前创建的块添加为回调

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

The block must NOT be called at that moment, but stored in the cell and only called it when the time is right. 那一刻不能调用该块,而应将其存储在单元中,并且仅在适当的时候调用它。 How would I go about this correctly? 我将如何正确处理?

Thank you very much. 非常感谢你。

Edit: What I'd also like to avoid is storing the parameters for the block in the cell and pass them upon calling, because that would require me to further specialize the cells unnecessarily. 编辑:我也想避免的是将块的参数存储在单元格中,并在调用时传递它们,因为这将需要我不必要地进一步专门化单元格。

It sounds like what you want is a block that calls your block, something like this: 听起来您想要的是一个可以调用您的块的块,如下所示:

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

But this is a rather odd and convoluted design. 但这是一个相当奇怪且令人费解的设计。 It seems like there is probably a way to write it with only one block, but it's hard to give a solution that specific without a better idea of what you're doing. 似乎只有一种方法可以编写它,但是如果不更好地了解自己在做什么,很难给出具体的解决方案。

The most straight forward way is to create a typedef containing how the block parameters should look like, then use it to declare a new property/ivar. 最直接的方法是创建一个typedef,其中包含块参数的外观,然后使用它来声明新的属性/ ivar。 The following sample code is copied from the Sensible TableView framework SCCellActions class: 以下示例代码是从Sensible TableView框架SCCellActions类复制的:

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

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

You could then set the property as follows: 然后可以按如下所示设置属性:

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

Similarly, you could declare a parameter as follows: 同样,您可以声明一个参数,如下所示:

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

In which case the method should be called like this: 在这种情况下,应按以下方式调用该方法:

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

This answer is based on Chuck's suggestion and describes the pitfalls I encountered realizing it. 该答案基于Chuck的建议,并描述了我在实现它时遇到的陷阱。

Creation: 创建:

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

doStuff is a local block, declared before the cells. doStuff是一个局部块,在单元格之前声明。 I was unable to add it directly to the cell, because I also needed a reference to the calling cell within the block. 我无法将其直接添加到单元格中,因为我还需要对块中调用单元格的引用。

Pitfall at this point: Class variables. 此时的陷阱:类变量。 A block will only retain...or rather 'copy'...local variables, but not class variables. 一个块将只保留...或更确切地说是“复制”局部变量,而不保留类变量。 Assuming that 'Cell' was a class variable and set by 'CreateCell', the block would work with the value of Cell at the time the block is executed. 假设“ Cell”是一个类变量,并由“ CreateCell”设置,则该块将在执行该块时使用Cell的值。

As such, it is important to remember to declare a local variable, which assumes the value of the class variable if necessary. 因此,重要的是要记住声明一个局部变量,该变量在必要时采用类变量的值。

Storage: 存储:

- (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;
}

Pitfall at this point: If the block is merely retained, the local block from the calling function will go out of scope and the program will fail with 'Bad Access'. 此时的陷阱:如果仅保留该块,则调用函数中的本地块将超出范围,并且程序将因“错误访问”而失败。 Copy resolves this problem. 复制可以解决此问题。

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. 当然,一旦使用完Block(在回调类的dealloc中),您就需要释放它,但这是已知的。

I hope this little explanation will save someone some grief. 我希望这个简短的解释可以减轻一些人的痛苦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM