Я определил набор макросов, чтобы визуально упростить мой код при создании операторов UIActionController
и UIAlertAction
. Макросы работают нормально, но есть одна ситуация, которая вызывает ошибки компилятора. Хотя существует простой обходной путь, я пытаюсь понять, почему возникают эти ошибки и как переписать макрос, чтобы исключить необходимость обходного пути.
Ниже определены два макроса. Макрос first включен только для того, чтобы пример кода компилировался.
Моя проблема касается макроса second . У него есть два аргумента. Один - это строка, а другой - actionBlock
(для 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.
ОБНОВЛЕНИЕ: Это также смущает логику отступа Xcode c, если в actionBlock есть условие. Для остроумия:
ALERT_DEFAULT_ACTION( @"Action 4a Title" ,
// code here, correct indentation
);
ALERT_DEFAULT_ACTION( @"Action 4b Title" ,
if ( true ) {
// code here, incorrect indentation
} // incorrect indenation
);