如何摆脱这种第 22 条军规的局面?

How to get out of this Catch 22 situation?

我遇到了无法解决的第 22 条军规问题,我正在使用 UIAlertCOntroller 向用户显示信息,并根据答案采取一些措施

if([NWTillHelper finishTransactionWithoutEmail] != 1) {
        if([NWTillHelper getCrmId] == nil) {
            //Step 1: Create a UIAlertController
            UIAlertController *userInfoCheck = [UIAlertController alertControllerWithTitle:@"No Customer Email!"
                                                                                   message: @"Do you want to proceed without customer email? No receipt will be sent out in this case!"
                                                                            preferredStyle:UIAlertControllerStyleAlert];

            //Step 2: Create a UIAlertAction that can be added to the alert
            UIAlertAction *Yes = [UIAlertAction
                                  actionWithTitle:@"Yes"
                                  style:UIAlertActionStyleDefault
                                  handler:^(UIAlertAction * action)
                                  {
                                      NSUserDefaults *tillUserDefaults = [NSUserDefaults standardUserDefaults];
                                      [tillUserDefaults setInteger:1 forKey:@"finishTransactionWithoutEmail"];
                                      [tillUserDefaults synchronize];
                                      [userInfoCheck dismissViewControllerAnimated:YES completion:nil];
                                  }];

            UIAlertAction *No = [UIAlertAction
                                 actionWithTitle:@"No"
                                 style:UIAlertActionStyleDefault
                                 handler:^(UIAlertAction * action)
                                 {
                                     [userInfoCheck dismissViewControllerAnimated:YES completion:nil];
                                 }];

            //Step 3: Add the UIAlertAction ok that we just created to our AlertController
            [userInfoCheck addAction: Yes];
            [userInfoCheck addAction: No];

            //Step 4: Present the alert to the user
            [self presentViewController:userInfoCheck animated:YES completion:nil];
            return;
        }
    }

我遇到的问题是最后一个 return 语句似乎是 运行 在完成块完成之前,我希望 return 以用户操作为条件,但是如果我把 return 放在 Yes alertAction 中,那么在用户有机会 select yes/no 之前,方法中下面的代码是 运行 所以我被卡住了我需要最后一个 return 停止下面的代码是 运行 但同时我需要等待完成块完成?我该如何处理这种情况,以便我在整个代码块下方的代码仅在用户 select 执行操作后才 运行?

您可以尝试将其附加到根视图控制器,例如:

//Step 4: Present the alert to the user
UIViewController *controller = [UIApplication sharedApplication].delegate.window.rootViewController;
[controller presentViewController:userInfoCheck animated:YES completion:nil];
return;

每当您看到接受 "handler" 块的 API 时,最好假设它们 运行 是异步的。这意味着源代码中的语句顺序不是操作顺序。

在这种情况下...

  1. presentViewController returns 立即(您的函数 returns 紧随其后),导致显示警报。
  2. 当用户坐在那里看着警告框时,应用程序继续旋转其主 运行 循环。 UIKit 跟踪触摸(即使它们没有可见效果),您的 UI 的其他元素可能在警报后面明显动画或对网络 activity 等非用户输入做出反应(这可能涉及也可能不涉及您自己的其他代码)。
  3. 用户点击警告框中的按钮,导致 UIKit 运行 您的是或否完成处理程序。

这意味着无论您想使用什么逻辑来响应用户的警报选择都不能写在显示警报的方法体中。您需要安排由于您的警报操作处理程序,此类代码 运行 。伪代码示例:

- (void)handleEmailChoice:(BOOL)proceedWithoutEmail {
    // do whatever depends on user choice
}

// elsewhere
UIAlertController *userInfoCheck = [UIAlertController alertControllerWithTitle:/*...*/];
UIAlertAction *yes = [UIAlertAction actionWithTitle:@"Yes"
                              style:UIAlertActionStyleDefault
                              handler:^(UIAlertAction * action)
                              {
                                 // set defaults, dismiss alert, then:
                                 [self handleEmailChoice:YES];
                              }];

UIAlertAction *no = [UIAlertAction actionWithTitle:@"No"
                             style:UIAlertActionStyleDefault
                             handler:^(UIAlertAction * action)
                             {
                                 // dismiss alert, then:
                                 [self handleEmailChoice:NO];
                             }];

[userInfoCheck addAction: yes];
[userInfoCheck addAction: no];
[self presentViewController:userInfoCheck animated:YES completion:nil];