Как выйти из этой ситуации с Catch 22?

У меня проблема Catch 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 кажется выполненным ДО завершения блоков завершения, и я хочу, чтобы возврат был условным для действия пользователя, но если я добавлю возвращение в Yes alertAction, тогда приведенный ниже код в методе запускается до того, как у пользователя есть возможность выбрать да / нет, поэтому я застрял, мне нужно последнее возвращение, чтобы остановить код ниже, чтобы быть запущенным, но в то же время мне нужно дождаться завершения блока завершения? Как я могу справиться с этой ситуацией, чтобы мой код под всем этим блоком кода запускался только после того, как пользователь выбрал действие?

2 ответа

Решение

Каждый раз, когда вы видите API, которые принимают блоки "обработчики", лучше предположить, что они работают асинхронно. Это означает, что порядок операторов в вашем исходном коде не является порядком операций.

В этом случае...

  1. presentViewController немедленно возвращается (и ваша функция возвращается сразу после этого), вызывая показ предупреждения.
  2. Приложение продолжает вращать свой основной цикл выполнения, пока пользователь сидит и смотрит на окно предупреждения. UIKit отслеживает прикосновения (даже если они не имеют видимого эффекта), другие элементы вашего пользовательского интерфейса могут заметно анимировать за оповещением или реагировать на не-пользовательские входные данные, такие как сетевая активность (которая может включать или не включать другой ваш собственный код).
  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];

Вы можете попробовать подключить его к контроллеру корневого представления, например:

//Step 4: Present the alert to the user
UIViewController *controller = [UIApplication sharedApplication].delegate.window.rootViewController;
[controller presentViewController:userInfoCheck animated:YES completion:nil];
return;
Другие вопросы по тегам