Как предотвратить текущий модемный активный контроллер?

У нас есть 2 контроллера: MainVC и ProfileVC. Из MainVC перейдите в ProfileVC с нажатием profileButton (левый элемент на панели навигации).

В профиле VC у нас есть две кнопки на панели навигации: назад к главному (leftItem) и откройте alertView (rightItem).

Итак, есть простой тест KIF (просто вечные левые правые краны на панели навигации):

- (void)testProfileButtons
    {
        [tester waitForAnimationsToFinishWithTimeout:0.3];
        while (true)
        {
            [tester tapScreenAtPoint:CGPointMake(20, 20)];
            [tester waitForTimeInterval:0.1];
            [tester tapScreenAtPoint:CGPointMake(380, 20)];
            [tester waitForTimeInterval:0.1];
            [tester tapScreenAtPoint:CGPointMake(20, 20)];
            [tester waitForTimeInterval:0.1];
        }
    }

Сбой приложения с ошибкой:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <UINavigationController: 0x7fe862ef82d0>.'

*** First throw call stack:
(
    0   CoreFoundation                      0x0000000110944c65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001105dabb7 objc_exception_throw + 45
    2   UIKit                               0x000000010f44b80d -[UIViewController _presentViewController:withAnimationController:completion:] + 3238
    3   UIKit                               0x000000010f44d6c1 __62-[UIViewController presentViewController:animated:completion:]_block_invoke + 132
    4   UIKit                               0x000000010fa5e5ae -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 217
    5   UIKit                               0x000000010fa5b8e5 -[_UIViewControllerTransitionContext _runAlongsideCompletions] + 123
    6   UIKit                               0x000000010fa5b670 -[_UIViewControllerTransitionContext completeTransition:] + 126
    7   UIKit                               0x000000010f2fe8a6 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke93 + 687
    8   UIKit                               0x000000010f387193 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 326
    9   UIKit                               0x000000010f36e0f6 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 209
    10  UIKit                               0x000000010f36e42c -[UIViewAnimationState animationDidStop:finished:] + 76
    11  UIKit                               0x000000011daf3fdf -[UIViewAnimationStateAccessibility animationDidStop:finished:] + 48
    12  QuartzCore                          0x000000010f03e892 _ZN2CA5Layer23run_animation_callbacksEPv + 308
    13  libdispatch.dylib                   0x0000000111c67964 _dispatch_client_callout + 8
    14  libdispatch.dylib                   0x0000000111c52a59 _dispatch_main_queue_callback_4CF + 704
    15  CoreFoundation                      0x00000001108ac1f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    16  CoreFoundation                      0x000000011086ddcb __CFRunLoopRun + 2043
    17  CoreFoundation                      0x000000011086d366 CFRunLoopRunSpecific + 470
    18  TurboChat UI Tests                  0x000000011b73ef69 -[KIFTestActor tryRunningBlock:complete:timeout:error:] + 425
    19  TurboChat UI Tests                  0x000000011b73f179 -[KIFTestActor runBlock:complete:timeout:] + 137
    20  TurboChat UI Tests                  0x000000011b73f304 -[KIFTestActor runBlock:timeout:] + 84
    21  TurboChat UI Tests                  0x000000011b73f73e -[KIFTestActor waitForTimeInterval:] + 174
    22  TurboChat UI Tests                  0x000000011b73c2ad -[TCProfileButtonsTest testProfileButtons] + 909
    23  CoreFoundation                      0x000000011083adec __invoking___ + 140
    24  CoreFoundation                      0x000000011083ac42 -[NSInvocation invoke] + 290
    25  XCTest                              0x000000011b79217a -[XCTestCase invokeTest] + 253
    26  XCTest                              0x000000011b792379 -[XCTestCase performTest:] + 150
    27  XCTest                              0x000000011b79bc35 -[XCTest run] + 260
    28  XCTest                              0x000000011b79108b -[XCTestSuite performTest:] + 379
    29  XCTest                              0x000000011b79bc35 -[XCTest run] + 260
    30  XCTest                              0x000000011b79108b -[XCTestSuite performTest:] + 379
    31  XCTest                              0x000000011b79bc35 -[XCTest run] + 260
    32  XCTest                              0x000000011b79108b -[XCTestSuite performTest:] + 379
    33  XCTest                              0x000000011b79bc35 -[XCTest run] + 260
    34  XCTest                              0x000000011b78e129 __25-[XCTestDriver _runSuite]_block_invoke + 56
    35  XCTest                              0x000000011b798edd -[XCTestObservationCenter _observeTestExecutionForBlock:] + 162
    36  XCTest                              0x000000011b78e060 -[XCTestDriver _runSuite] + 269
    37  XCTest                              0x000000011b78ea8d -[XCTestDriver _checkForTestManager] + 234
    38  XCTest                              0x000000011b79eb20 +[XCTestProbe runTests:] + 182
    39  Foundation                          0x000000010e5f21e5 __NSFireDelayedPerform + 387
    40  CoreFoundation                      0x00000001108ac174 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    41  CoreFoundation                      0x00000001108abd35 __CFRunLoopDoTimer + 1045
    42  CoreFoundation                      0x000000011086dd3d __CFRunLoopRun + 1901
    43  CoreFoundation                      0x000000011086d366 CFRunLoopRunSpecific + 470
    44  GraphicsServices                    0x00000001123a8a3e GSEventRunModal + 161
    45  UIKit                               0x000000010f30e8c0 UIApplicationMain + 1282
    46  TurboChat                           0x000000010cd1e75f main + 111
    47  libdyld.dylib                       0x0000000111c97145 start + 1
)

Я также получаю это при тестировании на реальном устройстве:

Presenting view controllers on detached view controllers is discouraged <TCProfileTableViewController: 0x14f6299c0>.

и получить alertView, появляющийся поверх MainVC, а не ProfileVC с черным экраном под ним.

Вот как мы представляем оповещение в ProfileVC:

- (IBAction)menuButtonPressed:(id)sender
{
    [self.navigationController presentViewController:self.menuAlert animated:YES completion:nil];
}

AlertView:

self.menuAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"%@?", NSLocalizedString(@"PROFILE_BTN_MENU", nil)]
                                                             message:nil
                                                      preferredStyle:UIAlertControllerStyleActionSheet];

Любые предложения?

Ответ 1

Я нашел решение для этого

- (IBAction)menuButtonPressed:(id)sender
{
    [self.parentViewController presentViewController:self.menuAlert animated:YES completion:nil];
}

Иногда появляется меню предупреждения, но оно не разбивает приложение и работает нормально. Ответ был обнаружен там: Предупреждение: -Доступные контроллеры представлений на отдельных контроллерах просмотров не поощряются

Ответ 2

Я думаю, вам нужно будет сначала отключить LENT viewcontroller, прежде чем вернуться с помощью текущего модального сегмента, элемент управления представлением активен, поэтому он сбой:

Используйте этот вызов после вызова из mainVC или что-то, что захотелось вернуться:

[self dismissViewControllerAnimated:NO completion:nil]

или

[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

или используйте push segue, он автоматически добавит кнопку возврата, которая автоматически добавит обратно функцию

Ответ 3

Может быть другой случай для других разработчиков:

Представляется ли целевой ViewController после подключения, инициируемого кнопкой? Пользователь может дважды щелкнуть, сделать два подключения и дважды открыть один и тот же ViewController, если у вас есть общий экземпляр указанного ViewController.

Предотвратите это, сделав что-то вроде этого:

var didSuccess = false

func success(result: LoginModel.Result) {
    if didSuccess {
        return
    }
    didSuccess = true
    present(MainTabBarController.sharedInstance, animated: true, completion: nil)
}

Или отключение кнопки во время подключения.

Ответ 4

Чтобы предотвратить это исключение. Просто отклоните текущий ViewController, чтобы вернуться к вызывающему ViewController, который вы отклоняете:

self.dismiss(animated: true, completion: nil)