【问题标题】:Objective-C - Storing block with parameters for callbackObjective-C - 使用回调参数存储块
【发布时间】:2012-12-12 07:47:47
【问题描述】:

我有一个通用例程,它需要一些参数。 比如:

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

现在效果不错...但是,它需要我传递的方法来对传递的单元格的 ID 进行切换/案例,我想避免这种情况。

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

我正在尝试做的事情:

声明一个功能块doStuff

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

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

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

此时不能调用该块,而应将其存储在单元格中,并且仅在适当的时候调用它。 我该如何正确处理?

非常感谢。

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

【问题讨论】:

    标签: objective-c ios callback


    【解决方案1】:

    听起来你想要的是一个调用你的块的块,像这样:

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

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

    【讨论】:

    • 这似乎总结了我正在尝试做的事情。这可能会让人觉得奇怪,但积木也是如此。我会尝试并给你反馈。谢谢你:)
    【解决方案2】:

    最直接的方法是创建一个 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];}];
    

    【讨论】:

    • 不,我认为这不是我想要的。你看,这个设置需要我进一步专门化我的单元格或进入 switch case 以确定与 ID 匹配的参数。无论如何,谢谢。
    【解决方案3】:

    这个答案基于 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 中),但这是给定的。

    我希望这个小小的解释可以减轻一些人的痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多