【问题标题】:Attempt to present UIViewController while a presentation is in progress!-Warning在演示过程中尝试演示 UIViewController!-警告
【发布时间】:2015-12-04 06:45:50
【问题描述】:

假设一个新的 iOS 项目,只有一个导航控制器(正确连接为入口点)和一个包含以下三行代码的重写 viewDidAppear():

            self.presentViewController(UIViewController(), animated: true, completion: nil)
            self.dismissViewControllerAnimated(true, completion: {})
            self.presentViewController(UIViewController(), animated: true, completion: nil)

执行时,该代码将引发警告“尝试在演示过程中演示 UIViewController!”尝试呈现第二个控制器时。

问题:为了在调用另一个控制器之前正确关闭控制器,我到底缺少什么?

【问题讨论】:

  • 如果你想关闭一个控制器然后执行一些后续操作,请将所有后续代码放在完成处理程序中以进行关闭。听起来你试图在关闭完成之前展示一个新的控制器?
  • 对不起,但不知何故,我找不到任何“跟随代码”放置在完成处理程序中的信息,以允许旧控制器被解散。还是您的意思是我需要在该处理程序中放置某种购买等待代码,以确保在调用下一个控制器之前控制器已被解除?
  • FIY:在 Rory McKinnel 发表评论后,我改进了这个问题
  • 我试过的都没有用。调用另一个糟糕的控制器并不是那么困难!我想我一定错过了一些基本的东西。我希望有人可以提供帮助,仅用三行代码就可以得到如此持久的问题真是太荒谬了
  • 从您的新代码中,您需要将每一行放在前一行的完成处理程序中,尽管顺序对我来说意义不大。

标签: ios swift uiviewcontroller ios8


【解决方案1】:

您需要在初始的 presentViewController 调用中添加某种延迟,如下所示:

override func viewDidAppear(animated: Bool) {
    presentViewController(UIViewController(), animated: true) { () -> Void in
        self.delay(0.1, closure: { () -> () in
            self.dismissViewControllerAnimated(true, completion: nil)
        })
    }
}


func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

似乎在动画真正完成之前调用了完成块。

【讨论】:

  • 它有助于摆脱阻碍。但是,当用您的建议替换现有的 presentViewController() 调用时,相关屏幕会被一遍又一遍地加载。
  • 我还遇到了另一个问题:第二个控制器的视图“不在窗口层次结构中”。但是,当从代码中删除第一个控制器时,不会提示此类消息。从代码中删除第一个控制器如何使第二个控制器视图出现在窗口层次结构中?我不明白(还)。
  • 使用您的代码建议调用两个通用控制器时已经存在该问题: override func viewDidAppear(animated: Bool) { presentViewController(UIViewController(), animated: true) { () -> Void在 self.delay(0.1,closure: { () -> () in self.dismissViewControllerAnimated(true, completion: nil) }) } presentViewController(UIViewController(), animated: true) { () -> Void in self.delay (0.1, 闭包: { () -> () in self.dismissViewControllerAnimated(true, completion: nil) }) } }
【解决方案2】:

假设您希望主控制器出现,呈现一个控制器,关闭控制器,再次呈现并关闭,那么您需要链接这些操作,以便它们按顺序发生。

为了防止它永远旋转,您还需要只在主控制器第一次出现时运行代码。

我不是 swift 编码器,但类似以下内容应该可以工作。检查以确保控制器正在呈现或被推上,然后它使用每个操作完成运行序列以开始下一个操作。这个守卫应该确保在每次解雇 viewDidAppear 被调用后,它在这些情况下不做任何事情。

var firstTime = true;

func presentThenDismiss(finalCompletion: (() -> Void)?)
{
    presentViewController(UIViewController(), animated: true, completion : { [weak self] Void in
        // On completion of the present, we dismiss it
        dispatch_async(dispatch_get_main_queue(), {
            self?.dismissViewControllerAnimated(true, completion: { Void in
                // On completion of the dismiss, we present another
                finalCompletion!()
            })
        })
    })
}

override func viewDidLoad() {
    super.viewDidLoad()


    // We only run the modal presentation code when being presented or
    // being pushed on, NOT when exposed by a model dismiss or pop
    //
    if (firstTime){
        firstTime = false;

        self.presentThenDismiss { () -> Void in
            self.presentThenDismiss { () -> Void in
            }
        }
    }
}

【讨论】:

  • if (isBeingPresented() || isMovingToParentViewController()) 中的块如果放在作为根控制器的控制器的 viewDidAppear 方法中,则永远不会被执行
  • @Basti 由于这是一个关闭并且是根目录,因此将示例更改为有一个标志,该标志检测第一次看到控制器。
  • 不幸的是,Xcode 已经对语法不满意了......而且我不喜欢重写一个经常调用的函数来执行只能执行一次的操作。对我来说看起来像个黑客
  • @Basti 如前所述,我不是一个敏捷的人,因此您可能需要调整代码。我相信是您在问题中从viewDidAppear 要求发生这种情况,如果您希望它发生一次,那么您必须按照说明放置一个警卫,因为您的要求多次调用viewDidAppear存在/解雇周期。也许您需要在问题中描述您的用例。现在我们都只是回答你问的问题,即如何让你的 3 行从viewDidAppear 正常工作?
  • 是的,你是对的。我假设 viewDidAppear() 是正确的地方,因为我在堆栈溢出的多个位置读取了它......但是我的用例是根据需要从一个“根”控制器实例化和关闭多个控制器。
猜你喜欢
  • 2013-10-15
  • 1970-01-01
  • 2012-12-03
  • 2012-11-18
  • 2014-04-24
  • 2014-06-12
  • 2013-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多