86

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 找到的不同解决方案,但均未成功。

4

17 回答 17

128

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

于 2014-09-24T17:42:55.523 回答
36

在目标 c 中:这解决了我在 mpmovieplayer 上呈现 viewcontroller 时的问题

- (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

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

    return topController;
}
于 2015-03-20T09:12:59.197 回答
36

斯威夫特 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

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

于 2016-10-22T16:50:38.343 回答
17

斯威夫特 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)
于 2017-06-04T16:49:01.970 回答
14

对于 SWIFT

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}
于 2016-07-12T11:14:11.647 回答
13

您只需要延迟执行选择器 - (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) 
}
于 2016-12-08T00:59:11.447 回答
7

斯威夫特 4

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}
于 2017-09-18T13:03:22.397 回答
3

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

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }
于 2020-03-18T13:02:43.913 回答
2

对于 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}
于 2017-01-08T13:20:21.953 回答
2

在用户打开深层链接后呈现控制器时出现此错误。我知道这不是最好的解决方案,但如果你在短时间内,这里是一个快速修复 - 只需将你的代码包装在asyncAfter

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

它会给你的演示控制器时间来调用viewDidAppear

于 2019-04-01T15:03:26.150 回答
1
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

于 2016-10-02T21:10:53.270 回答
1

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

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}
于 2017-07-02T11:57:51.153 回答
1

UINavigationController当您拥有or时,此处 topViewController 的所有实现都不是完全支持的情况UITabBarController,对于这两个您需要稍微不同的处理:

因为你需要一个不同的实现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
    }
}
于 2017-11-25T21:34:14.853 回答
1

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

于 2019-06-02T10:16:56.007 回答
1

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)
}
于 2020-01-06T08:39:54.557 回答
1

斯威夫特 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)
于 2020-02-08T11:52:50.383 回答
0

与其寻找顶视图控制器,不如使用

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

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

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

于 2017-12-20T14:54:44.770 回答