ios - 带有 actionBlock 的宏会导致编译器错误
问题描述
我已经定义了一组宏来在创建UIActionController
和UIAlertAction
语句时直观地简化我的代码。宏工作正常,但有一种情况会导致编译器错误。尽管有一个简单的解决方法,但我试图了解为什么会发生这些错误以及如何重写宏以消除对解决方法的需要。
下面定义了两个宏。包含第一个宏仅是为了编译示例代码。
我的问题涉及第二个宏。它有两个论点。一个是字符串,另一个是actionBlock
(对于 a completionHandler
)。如果actionBlock
包含带有数组的语句或带有多个参数的方法调用(类似于数组),编译器会报错。如图所示,可以通过添加一对括号来消除错误。
- (void)macroTest
{
#define ALERT_CREATE( title, msg ) \
UIAlertController *alertController = \
[UIAlertController alertControllerWithTitle:title \
message:msg preferredStyle:UIAlertControllerStyleAlert]
#define ALERT_DEFAULT_ACTION( title, actionBlock ) \
[alertController addAction:[UIAlertAction actionWithTitle:title \
style:UIAlertActionStyleDefault \
handler:^(UIAlertAction *action) { actionBlock } ]]
// Example code
ALERT_CREATE( @"Alert Title", @"Alert Message" );
// This example is fine (no errors):
ALERT_DEFAULT_ACTION( @"Action 1 Title" , /* actionBlock */
int i = 1;
i++;
);
// This results in error: Use of undeclared identifier 'ALERT_DEFAULT_ACTION'
ALERT_DEFAULT_ACTION( @"Action 2a Title" ,
// Another error: Too many arguments provided to function-like macro invocation
NSArray *test = @[ @"1", @"2" ]; // not okay
);
ALERT_DEFAULT_ACTION( @"Action 2b Title" ,
// The same code as 2a, but with parens, is okay
NSArray *test = (@[ @"1", @"2" ]); // this is okay (with parens)
);
ALERT_DEFAULT_ACTION( @"Action 3 Title" ,
// Parentheses are needed here, too, to avoid error
NSString *str1 = [NSString stringWithFormat:(@"format %@", @"arg")]; NSString *str2 = ([NSString stringWithFormat:@"format %@", @"arg"]);
);
`enter code here`// The next line displays the alert. It's commented out to avoid errors in this example.
// [self presentViewController:alertController animated:YES completion:nil];
}
为什么编译器会抱怨,我该如何重写第二个宏,这样我就不必在其 actionBlock 中的某些语句中添加括号?我正在使用 Xcode 11.3。
更新:如果 actionBlock 中有条件,它也会混淆 Xcode 的缩进逻辑。以机智:
ALERT_DEFAULT_ACTION( @"Action 4a Title" ,
// code here, correct indentation
);
ALERT_DEFAULT_ACTION( @"Action 4b Title" ,
if ( true ) {
// code here, incorrect indentation
} // incorrect indenation
);
解决方案
我的问题应该被标记为重复,因为有几个类似的问题有答案。诀窍是使用好的搜索词(提示,搜索:在宏中传递一个块)。
解决方案是使用可变参数函数(“...”和VA_ARGS)。宏的最后一个参数吞噬了块中的所有内容,包括逗号,正如这篇出色的文章中所解释的那样:将块作为参数发送给宏 https://mort.coffee/home/obscure-c-features/
如果该链接成为孤立链接,那么重点是:
预处理器支持可变参数宏;可以接受无限量参数的宏。它们的实现方式是通过VA_ARGS标识符提供任何额外的参数(在宏定义中由 ... 表示) ;VA_ARGS被替换为用逗号分隔的所有额外参数。[这将] 一段带有无保护逗号的代码块传递给宏。
那篇文章归功于 2012 年的这个早期解决方案: https ://stackoverflow.com/a/13842612/1578823所以,+1。
这是我的固定宏:
#define ALERT_DEFAULT_ACTION( title, ... /* actionBlock */ ) \
[alertController addAction:[UIAlertAction actionWithTitle:title \
style:UIAlertActionStyleDefault \
handler:^(UIAlertAction *action) { {__VA_ARGS__} /* actionBlock */ }]]
这并不能解决括号缩进不正确的问题(例如,在 if 语句中)。这对 Xcode 来说太令人困惑了。
ALERT_DEFAULT_ACTION( @"title",
NSArray *test = @[ @"1", @"2" ]; // commas okay now
if ( true ) {
test = test; // incorrect indentation
} // incorrect indentation
test = test;
);
推荐阅读
- javascript - 从 2018-05-29T04:12:35Z 到其他时间的日期和时间转换
- xml - 我可以使用什么 API 来获取 FAA NOTAMS,或者我找到的这个 API 有用吗?
- jquery - 将直线的 x 和 y 数组转换为抛物线
- heroku - 防止heroku在子域上从http重定向到https
- mysql - 使用多个 sum(if(condition)) 优化 mysql 查询
- python - Python弹弓模型
- c++ - 如果不使用“新”生成实例该怎么办
- php - 我在尝试获取非对象的属性时遇到错误
- python - 如何从两个列表中获取所有组合?
- c++ - c ++ 类方法指针作为函数参数