在iOS8-iOS11中,从操作表的代理模态呈现视图控制器

58

我注意到在iPad上的iOS8 beta 3 (更新: 在iOS 11.2中仍然存在)中,当试图从UIActionSheet的委托方法中呈现一个视图控制器时,"没有任何事情"发生,并且会输出一条日志消息到调试控制台,指出在转换alert controller时尝试了呈现操作:

Warning: Attempt to present <UIViewController: 0x...> on <ViewController: 0x...> which is already presenting <UIAlertController: 0x...>
9个回答

138

更新:从iOS 9 SDK开始,UIActionSheet被弃用,因此不要期望修复这个问题。最好在可能的情况下开始使用UIAlertController


这个问题似乎来自于苹果公司使用UIAlertController内部实现警告视图和操作表的功能。这个问题主要出现在iPad上和操作表中,因为在iPad上,操作表会作为一个弹出视图显示在指定的视图中,并且苹果会沿着响应链寻找一个视图控制器并调用presentViewController:animated:completion:与内部的UIAlertController。这个问题在iPhone上和警告视图一起出现的时候不太明显,因为在那里苹果实际上创建了一个单独的窗口、一个空的视图控制器,并在其上方呈现了内部的UIAlertController,所以它似乎不会干扰其他的呈现。

我已经为这个问题提交了错误报告:rdar://17742017。请重复报告并让苹果知道这是一个问题。

作为解决方法,我建议延迟呈现到下一个运行循环中,使用以下方法:

dispatch_async(dispatch_get_main_queue(), ^ {
    [self presentViewController:vc animated:YES completion:nil];
});

即便如此,它对我来说仍然无法工作。弹出窗口失败了。iOS8 = 损坏了一切。 - Michael Chourdakis
很难想象这个错误仍然存在。@leo-natan,你有苹果的更新吗? - Pichirichi
@Pichirichi 不,这个问题仍然在苹果公司的处理中,并且在8.1 b1上可以重现。 - Léo Natan
1
在iPad上的iOS 8.1b2中,此解决方法适用于UIActionSheetshowFromRect: - Maen
@Michael 我猜这个评论可能太晚了,但你可以尝试使用dispatch_after,在我的经验中,dispatch_async并不总是在runloop之外调度。 - iur
显示剩余5条评论

31

你可以尝试在

执行任务(展示视图控制器)时

这样做

- (void)      actionSheet:(UIActionSheet *)actionSheet
didDismissWithButtonIndex:(NSInteger)buttonIndex {}

而不是

- (void) actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex {}

正如@LeoNatan所说,"该问题似乎来自于苹果公司在内部使用UIAlertController来实现警报视图和动作表的功能"。因此,您必须等待操作表被解除后,再呈现所需的视图控制器。

@LeoNatan的解决方案只是在主线程上阻塞UI,因此它还将确保在操作表被解除后呈现视图控制器。


1
我的解决方案不会阻塞主线程。在didDismiss中呈现会导致相同的问题。 - Léo Natan
延迟是阻塞的相反。 - Léo Natan
1
@HernanArber 是的,我对iOS 8 SDK有很多疑问。 - Kjuly
4
这似乎是最佳解决方案,我觉得结果也更自然。 - Bms270
UIActionSheet在iOS 8中已被弃用,因此这显然不再是一个有效的答案。感谢苹果!...什么也没有。 - Ash
显示剩余6条评论

4

很遗憾,这段代码对我来说不起作用,我认为这是因为我的问题不是直接调用presentController方法,而是在prepareForSegue方法中调用,因此使用

[segue destinationViewController]

我注意到如果segue是“push”类型,一切都正常工作,但如果是“modal”,仅在iPad上,我会遇到错误。
然后我在segue面板中发现了一些新选项,并选择了“当前上下文”作为演示选项来解决我的问题。
我希望这对其他人有所帮助......这是有关该选项的屏幕截图。

2

我曾经遇到过同样的问题。我在我的appdelegate中创建了一个单独的窗口用于警告和操作表,并在其上展示了这些警告。这对我有效!

   self.alertWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.alertWindow.backgroundColor = [UIColor clearColor];
  UIViewController *dummy = [[UIViewController alloc] init];
  [self.alertWindow setRootViewController:dummy];

你可以表示为:

[[myAppDelegate appDelegate].alertWindow makeKeyAndVisible];
  [[myAppDelegate appDelegate].alertWindow.rootViewController presentViewController:alertController animated:YES completion:nil];

请勿以答案形式发布。您可以提出另一个问题。 - Jaykumar Patel

2
我用以下代码在Swift 3中解决了这个问题。
  DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }

1
使用。
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex

代替

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex

操作视图呈现在当前视图控制器之上,这就导致了警告/错误。当调用didDismiss时,操作视图已经被解除显示,因此完全没有问题:))


这个回答和 @Kjuly 的一样。当我提出/回答问题时,系统在 didDismissWithButtonIndex: 上显示了相同的警报。 - Léo Natan
抱歉,我那时候没有看到那个答案 :) - zurakach

1
发布一个


[self.navigationController dismissViewControllerAnimated:YES completion:nil];

在。
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 

在尝试呈现另一个模态视图之前,这对我很有效。


1
你好,欢迎来到stackoverflow!请将你的答案格式化为更易读的格式,并尽可能提供更多的解释。 - Yohanes Khosiawan 许先汉

0

尝试一下

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    // action sheet presentation
    // or modal view controller presentation
    // or alert view presentation
}];

0
在iOS 8中,苹果内部使用UIAlertController来实现警告视图和操作表的功能。因此,当您想要在委托方法中显示UIActionSheet或UIAlertView后以模态方式显示UIViewController时,可以使用它。
(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex

并且

(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

你必须首先按照以下方式解除 UIAlertController:

if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0"))
{
    UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    [vc dismissViewControllerAnimated:NO completion:^{

    }];
}

现在你可以在iOS 8中呈现一个模态的UIViewController。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接