将Objective-C块声明为变量的最佳实践

时间:2017-03-07 11:44:17

标签: ios objective-c objective-c-blocks

关于将块声明为变量的最佳做法,我有一个问题。

最初我像这样写了我的块变量:

id actionHandler = ^(UIAlertAction * action) {
    // Handling code
};

稍后使用:

UIAlertAction *action = [UIAlertAction actionWithTitle:@"Title"
                                                 style:UIAlertActionStyleDefault
                                               handler:actionHandler];

但是当我遇到Apple's Working With Blocks指南时,我看到我可以像这样重写它:

void (^actionHandler)(UIAlertAction * action) = ^(UIAlertAction * action) {
    // Handling code
};

这是正确的吗?申报的方式?在我看来,这不是可读的,但我没有很多Objective-C的经验。那么将块声明为变量的最佳实践是什么?

编辑:好的,谢谢大家的澄清!通过 amin-negm-awad 和其他人将typedef定义为shown似乎也是一种不错的替代方法。

3 个答案:

答案 0 :(得分:3)

这里没有一个通用的答案:当您将块变量声明为id时,您不再拥有与块关联的编译时信息,因此手动调用它会产生问题:

id myHandler = ^(NSString *str) {
    NSLog(@"%@", str);
};
// Error: Called object type id is not a function or function pointer
myHandler(@"Hello");

如果您想从代码中直接调用块,则需要将其强制转换为块。

另一方面,如果您仅声明一个块变量,以便可以将其传递给以块作为参数的函数,则使用id提供更易读的方法。

答案 1 :(得分:2)

除了dasblinkenlicht提到的问题之外,我想问一个修辞问题:

您可能知道可以替换此代码......:

NSString *string = @"All about types";

...使用此代码:

id string = @"All about types";
你会这样做吗?我敢肯定,你没有。

那么为什么要将var的“类型”版本更改为id版本?唯一的原因是,块类型的语法是不方便的,不易读取(并且不易编写)。我总是定义一个具体类型来摆脱不熟悉的语法:

typedef void (^ActionHandlerType)(UIAlertAction * action);

然后:

ActionHandlerType actionHandler = ^(UIAlertAction * action) {
  // Handling code
};

为了清楚起见:id非常适合使用Objective-C消息传递的动态特性。但块执行既不是后期限制。块的参数也不能改变其数量或类型,因此没有动态绑定。这是一个简单的调用,固定数量的参数,固定类型。因此,id的使用可能是块的对象性质的副作用。但这不是一种用途,而是用途。

BTW:如果在参数列表中使用具体类型,Xcode可以自动完成参数的语法。使用id这是不可能的。明显。

答案 2 :(得分:1)

如果在此上下文中使用id,编译器将不会检查您声明的块的类型是否与方法所期望的块的类型匹配。如果你不小心让块错误,很难调试,当方法试图使用块时可能会发生...

因此,如果你永远不会犯错误,请使用id,但如果像我一样,你确实提供了正确的类型,这样编译器可以在你做的时帮助你。

为了使其更容易,因此更不容易出错,请使用typedef,例如:

typedef void (^AlertActionHandler)(UIAlertAction * action);
...

AlertActionHandler actionHandler = ^(UIAlertAction * action) { ...