警告:尝试在其视图不在窗口层次结构中的 * 上呈现 * - swift

Posted

技术标签:

【中文标题】警告:尝试在其视图不在窗口层次结构中的 * 上呈现 * - swift【英文标题】:Warning: Attempt to present * on * whose view is not in the window hierarchy - swift 【发布时间】:2014-11-19 07:01:03 【问题描述】:

我正在尝试提供ViewController如果数据模型中有任何保存的数据。但我收到以下错误:

警告:尝试在其视图不在窗口层次结构中的 * 上呈现 *"

相关代码:

override func viewDidLoad() 
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0)
        print("Inga resultat")
     else 
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    

我尝试了使用 Google 找到的不同解决方案,但均未成功。

【问题讨论】:

你在 Storyboard 中连接你的 ViewController 了吗?你在这里使用 NavigationController 吗? 如果我在 Storyboard 中连接了我的 ViewController,这对你意味着什么?我没有使用NavigationController@derdida 尝试:ViewDidLoad中的self.addChildViewController(childController: UIViewController) 这会产生错误。它需要在“类型名称”(UIViewController 部分)之后调用成员名称或构造函数。 @derdida 你在哪里写的?在 MainViewController 的 ViewDidLoad 中? 【参考方案1】:

使用主线程呈现和关闭视图控制器对我有用。

DispatchQueue.main.async  self.present(viewController, animated: true, completion: nil) 

【讨论】:

【参考方案2】:

Swift 5.1

let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
let appDeleg = UIApplication.shared.delegate as! AppDelegate
let root = appDeleg.window?.rootViewController as! UINavigationController
root.pushViewController(mainViewController, animated: true)

【讨论】:

【参考方案3】:

Swift 方法,并提供演示。

func topMostController() -> UIViewController 
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) 
        topController = topController.presentedViewController!
    
    return topController


func demo() 
    let vc = ViewController()
    let nav = UINavigationController.init(rootViewController: vc)
    topMostController().present(nav, animated: true, completion: nil)

【讨论】:

【参考方案4】:

前面的答案与应该呈现视图的视图控制器 1) 尚未添加到视图层次结构中,或 2) 不是顶部视图控制器的情况有关。 另一种可能性是,应该在另一个警报已经出现但尚未解除的同时显示一个警报。

【讨论】:

【参考方案5】:

我在用户打开深层链接后呈现控制器时收到此错误。 我知道这不是最好的解决方案,但如果您在短时间内可以快速解决 - 只需将您的代码包装在 asyncAfter:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute:  [weak self] in
                                navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                            )

您的演示控制器将有时间致电viewDidAppear

【讨论】:

【参考方案6】:

您只需要延迟执行选择器 - (0 秒有效)。

override func viewDidLoad() 
    super.viewDidLoad()
    perform(#selector(presentExampleController), with: nil, afterDelay: 0)


@objc private func presentExampleController() 
    let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
    let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
    present(exampleVC, animated: true) 

【讨论】:

非常感谢。我被这个问题困了一个多小时。 谢谢... @objc func presentExampleController() 我认为这是一个了不起的答案! 这是一个 hack(现在可能有效),但会让您在意外情况下遇到问题。【参考方案7】:

不用找顶视图控制器,可以使用

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

其中 viewController 是您要呈现的控制器 这在层次结构中有不同类型的视图(如 TabBar、NavBar)时很有用,尽管其他视图似乎是正确的,但更像是 hackish

其他演示风格可以在apple doc找到

【讨论】:

【参考方案8】:

当您有UINavigationControllerUITabBarController 时,这里所有topViewController 的实现都不是完全支持的情况,对于这两种情况,您需要稍微不同的处理方式:

对于UITabBarControllerUINavigationController,您需要不同的实现。

这是我用来获取 topMostViewController 的代码:

protocol TopUIViewController 
    func topUIViewController() -> UIViewController?


extension UIWindow : TopUIViewController 
    func topUIViewController() -> UIViewController? 
        if let rootViewController = self.rootViewController 
            return self.recursiveTopUIViewController(from: rootViewController)
        

        return nil
    

    private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? 
        if let topVC = from?.topUIViewController()  return recursiveTopUIViewController(from: topVC) ?? from 
        return from
    


extension UIViewController : TopUIViewController 
    @objc open func topUIViewController() -> UIViewController? 
        return self.presentedViewController
    


extension UINavigationController 
    override open func topUIViewController() -> UIViewController? 
        return self.visibleViewController
    


extension UITabBarController 
    override open func topUIViewController() -> UIViewController? 
        return self.selectedViewController ?? presentedViewController
    

【讨论】:

【参考方案9】:

斯威夫特 4

func topMostController() -> UIViewController 
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) 
        topController = topController.presentedViewController!
    
    return topController

【讨论】:

解释和示例会很有帮助@AllenWixted【参考方案10】:

我尝试了很多方法!唯一有用的是:

if var topController = UIApplication.shared.keyWindow?.rootViewController

  while (topController.presentedViewController != nil)
  
    topController = topController.presentedViewController!
  

【讨论】:

【参考方案11】:

此时,在您的代码中,仅创建了视图控制器的视图,但未将其添加到任何视图层次结构中。如果您想尽快从该视图控制器呈现,您应该在viewDidAppear 中进行,以确保最安全。

【讨论】:

如果我把它放在viewDidAppear中,那么当我关闭presentedViewController时,它会再次调用viewDidAppear方法并再次呈现viewController。我有一个在呈现之前放置条件语句的解决方法,但是有什么办法可以代替条件语句? 我会说,当屏幕出现时尝试呈现另一个模式是一种奇怪的行为,所以状态布尔并不是最糟糕的解决方案。同时,想想您需要显示模式的根本原因,看看您是否可以访问该信息。 如果在viewWillAppear中进行,开始演示时会出现正在演示中的情况。另一种方法是将其放在 viewWillAppear 中,但使用 ios 8 中的新transitionCoordinator 属性在过渡完成中添加代码。更多信息可以在这里找到developer.apple.com/library/prerelease/ios/documentation/UIKit/…【参考方案12】:

斯威夫特 3.

调用此函数以获取最顶层的视图控制器,然后让该视图控制器出现。

func topMostController() -> UIViewController 
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
        while (topController.presentedViewController != nil) 
            topController = topController.presentedViewController!
        
        return topController
    

用法:

let topVC = topMostController()
let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
topVC.present(vcToPresent, animated: true, completion: nil)

【讨论】:

感谢@Jacob Davis!我用它来展示 alertController 因为我收到了警告:尝试展示...... 这非常有用。一些正在呈现控制器但屏幕没有出现的东西。突然它被解雇了。还有其他代码需要实现吗?请建议【参考方案13】:

适用于 swift 3.0 及以上版本

public static func getTopViewController() -> UIViewController?
if var topController = UIApplication.shared.keyWindow?.rootViewController

  while (topController.presentedViewController != nil)
  
    topController = topController.presentedViewController!
  
  return topController

return nil

【讨论】:

【参考方案14】:

斯威夫特 3

作为一个新手,我不断出现这种情况,发现当前加载的模式视图可以被关闭,但如果您不需要显示模式,最好切换到根控制器。

我在用这个

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
present(vc, animated: false, completion: nil)

将它与我的 tabController 一起使用:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//show window
appDelegate.window?.rootViewController = view

如果您需要在多个故事板屏幕之间切换,只需调整为视图控制器即可。

【讨论】:

【参考方案15】:
let storyboard = UIStoryboard(name: "test", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)

这似乎可以确保它是最顶部的视图。

我遇到了一个错误

警告:尝试在其视图不在窗口层次结构中的 myapp.testController: 0x7fdd01703690 上呈现 myapp.testController: 0x7fdd01703990!

希望这可以帮助其他人使用 swift 3

【讨论】:

【参考方案16】:

对于 SWIFT

func topMostController() -> UIViewController 
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) 
        topController = topController.presentedViewController!
    
    return topController

【讨论】:

谢谢!这是为我解决此错误的唯一方法。我试图在视图完全加载之后(在 Xcode 8 / iOS 10 中)从手势识别器触发的函数中呈现模态 VC。奇怪的是,这个函数返回的topControllerself在尝试直接使用self.presentViewController(myModalVC)呈现时完全相同的VC,但是当我使用你的函数传入呈现的VC时没有视图层次错误。跨度> 【参考方案17】:

在目标 c 中: 这解决了我在 mpmovieplayer 上展示 viewcontroller 时遇到的问题

- (UIViewController*) topMostController

    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) 
        topController = topController.presentedViewController;
    

    return topController;

【讨论】:

以上是关于警告:尝试在其视图不在窗口层次结构中的 * 上呈现 * - swift的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Forms 警告:尝试使用 iOS 图像/手势识别器在其视图不在窗口层次结构中的 * 上呈现 *

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

警告:尝试在视图不在窗口层次结构中的 **.ViewController 上呈现 ZMNavigationController