将 Objective-C 块声明为变量的最佳实践
Best practice to declare Objective-C blocks as variable
我有一个关于将 块声明为变量的最佳实践的问题。
最初我这样写我的块变量:
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
};
这是'correct'的申报方式吗?在我看来,这不是可读的,但我对 Objective-C 没有太多经验。那么将块声明为变量的最佳做法是什么?
编辑: 好的,谢谢大家的澄清! amin-negm-awad 和其他人将 typedef
定义为 似乎也是一个很好的替代方法。
这里没有万能的答案:当您将块变量声明为 id
时,您不再拥有与您的块关联的编译时信息,因此手动调用它会出现问题:
id myHandler = ^(NSString *str) {
NSLog(@"%@", str);
};
// Error: Called object type id is not a function or function pointer
myHandler(@"Hello");
如果您想从您的代码中直接调用该块,您需要将其转换回一个块。
另一方面,如果您只声明一个块变量以便将其传递给将块作为参数的函数,则使用 id
提供了一种更具可读性的方法。
除了dasblinkenlicht提到的问题我想问一个反问:
您可能知道可以替换此代码……:
NSString *string = @"All about types";
... 使用此代码:
id string = @"All about types";
你愿意吗?我敢肯定,你不知道。
那么为什么要将 var 的 "typed" 版本更改为 id
版本呢?唯一的原因是,块类型的语法不方便且不易阅读(也不易编写)。我总是定义一个具体的类型来摆脱不方便的语法:
typedef void (^ActionHandlerType)(UIAlertAction * action);
然后:
ActionHandlerType actionHandler = ^(UIAlertAction * action) {
// Handling code
};
明确一点:id
非常适合使用 Objective-C 消息传递的动态特性。但是块执行既不是后期约束。块的参数也不能改变它的数量或类型,所以没有什么可以动态绑定的。这是一个简单的调用,具有固定数量的参数,固定类型。因此,id
的使用可能是块对象性质的副作用。但这不是一种用法,这是有意的。
顺便说一句:如果您在参数列表中使用具体类型,Xcode 可以自动完成参数的语法。使用 id
这是不可能的。显然。
如果您在此上下文中使用 id
,编译器将不会检查您声明的块类型是否与方法期望的块类型匹配。如果你不小心把块弄错了,很难调试,当方法试图使用块时,事情可能会发生......
因此,如果您从不犯错,请选择 id
,但如果您像我一样提供了正确的类型,那么编译器可以在您犯错时帮助您。
为了更简单,从而更不容易出错,请使用 typedef,例如:
typedef void (^AlertActionHandler)(UIAlertAction * action);
...
AlertActionHandler actionHandler = ^(UIAlertAction * action) { ...
我有一个关于将 块声明为变量的最佳实践的问题。
最初我这样写我的块变量:
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
};
这是'correct'的申报方式吗?在我看来,这不是可读的,但我对 Objective-C 没有太多经验。那么将块声明为变量的最佳做法是什么?
编辑: 好的,谢谢大家的澄清! amin-negm-awad 和其他人将 typedef
定义为
这里没有万能的答案:当您将块变量声明为 id
时,您不再拥有与您的块关联的编译时信息,因此手动调用它会出现问题:
id myHandler = ^(NSString *str) {
NSLog(@"%@", str);
};
// Error: Called object type id is not a function or function pointer
myHandler(@"Hello");
如果您想从您的代码中直接调用该块,您需要将其转换回一个块。
另一方面,如果您只声明一个块变量以便将其传递给将块作为参数的函数,则使用 id
提供了一种更具可读性的方法。
除了dasblinkenlicht提到的问题我想问一个反问:
您可能知道可以替换此代码……:
NSString *string = @"All about types";
... 使用此代码:
id string = @"All about types";
你愿意吗?我敢肯定,你不知道。
那么为什么要将 var 的 "typed" 版本更改为 id
版本呢?唯一的原因是,块类型的语法不方便且不易阅读(也不易编写)。我总是定义一个具体的类型来摆脱不方便的语法:
typedef void (^ActionHandlerType)(UIAlertAction * action);
然后:
ActionHandlerType actionHandler = ^(UIAlertAction * action) {
// Handling code
};
明确一点:id
非常适合使用 Objective-C 消息传递的动态特性。但是块执行既不是后期约束。块的参数也不能改变它的数量或类型,所以没有什么可以动态绑定的。这是一个简单的调用,具有固定数量的参数,固定类型。因此,id
的使用可能是块对象性质的副作用。但这不是一种用法,这是有意的。
顺便说一句:如果您在参数列表中使用具体类型,Xcode 可以自动完成参数的语法。使用 id
这是不可能的。显然。
如果您在此上下文中使用 id
,编译器将不会检查您声明的块类型是否与方法期望的块类型匹配。如果你不小心把块弄错了,很难调试,当方法试图使用块时,事情可能会发生......
因此,如果您从不犯错,请选择 id
,但如果您像我一样提供了正确的类型,那么编译器可以在您犯错时帮助您。
为了更简单,从而更不容易出错,请使用 typedef,例如:
typedef void (^AlertActionHandler)(UIAlertAction * action);
...
AlertActionHandler actionHandler = ^(UIAlertAction * action) { ...