Swift - 如何从viewController访问AppDelegate窗口

30

我在我的应用程序中做了一个新手引导流程,并想添加一个跳过按钮。 该按钮位于viewController上,因此我想通过访问app delegate窗口来将其移动到另一个viewController。

然而,它一直给我一个错误,指出AppDelegate.Type没有名为"window"的成员。

@IBAction func skipWalkthrough(sender: AnyObject) {
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    AppDelegate.window!.rootViewController = RootViewController   
}

这种方法有什么问题吗?

提前感谢!


你也可以尝试获取可见的视图控制器。 - Yogesh Patel
8个回答

57

你打错字了,应该是appDelegate而不是AppDelegate。像这样:

@IBAction func skipWalkthrough(sender: AnyObject) {
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    appDelegate.window!.rootViewController = RootViewController   
}

Swift 3.2

@IBAction func skipWalkthrough(_ sender: AnyObject) {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.window!.rootViewController = controller
    }

好的,没错,这是一个愚蠢的错误!顺便说一下,现在 RootViewController 出了问题,如何访问在 storyboard 中声明的这个视图控制器呢?我猜想创建一个新实例不是一个好主意吧?我的意思是 RootViewController() 会导致黑屏,所以应该有另外一种方法来访问这个控制器。 - theDC
以下是我在代码中的实现方式:let storyboardId = "LoginStoryboardIdentifier" self.window?.rootViewController = self.window?.rootViewController?.storyboard?.instantiateViewControllerWithIdentifier(storyboardId) as? UIViewController - Stefan Salatic
功能完美,但在注意到内存消耗时,我发现当我用(b)替换根视图控制器(a)时,没有看到内存减少。 这意味着(a)没有从内存中清除,对吗? 如何首先将其从内存中清除,然后显示(b)控制器? - Talha Ahmad Khan

20

这适用于使用或不使用Storyboard的情况,且支持 Swift 3+

let appDelegate = UIApplication.shared.delegate as? AppDelegate
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeController = mainStoryboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
appDelegate?.window?.rootViewController = homeController

2
Swift 5+ 还支持这个吗?我好像无法让它正常运行起来,这一行代码中的 appDelegate?.window 报错了,提示不能在 'any' 类型的非可选值上使用可选链,修复它会出现其他错误。 - Joseph Astrahan

11

Swift 3

这是一个更好的方式:

    if let window = NSApplication.shared().windows.first {
        window.acceptsMouseMovedEvents = true;
    }

1
NSApplication在MacOS中使用,这个问题标记在iOS中。 - Yogesh Patel

10

appDelegate.window!.rootViewControllerSwift 5中无法正常工作。

以下是可行的代码

添加以下扩展

extension UIWindow {
    static var key: UIWindow! {
        if #available(iOS 13, *) {
            return UIApplication.shared.windows.first { $0.isKeyWindow }
        } else {
            return UIApplication.shared.keyWindow
        }
    }
}

用途

let mainSB = UIStoryboard(name: "Main", bundle: nil)
                    
if let RootVc = mainSB.instantiateViewController(withIdentifier: "NavigationController") as? UINavigationController{
    UIWindow.key.rootViewController = RootVc
}

UIWindow.key // to access only window

1
这是如何在Swift5、iOS 13及以上版本中访问UIWindow实例以设置其rootViewController或呈现任何UIView的方法。谢谢伙计。 - Suhail
@Suhail 我忘记添加 window.makeKeyAndVisible() 这一行代码了,请查看我的更新答案,它一定能正常工作 :) - Nikunj Kumbhani

5

您还可以使用条件绑定来访问window对象。

if let window = UIApplication.shared.windows.first {
    // use window here.
}

2

您正在使用协议名称(即AppDelegate),而不是实例:

应该是:

appDelegate.window!.rootViewController = RootViewController   

2

您可以从应用程序的任何地方访问选项卡栏。请使用以下内容:

最初的回答:

let appDelegate = UIApplication.shared.delegate as! AppDelegate

if let tabBarController = appDelegate.window!.rootViewController as? UITabBarController {
    if let tabItems = tabBarController.tabBar.items {
       let tabItem = tabItems[2]
       tabItem.badgeValue = "5" //enter any value
    }
}

1
这个解决方案适用于以下情况: 在登录/注册后以编程方式添加UITabbarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window!.rootViewController = tabs
appDelegate.window!.makeKeyAndVisible()

虽然这段代码片段是受欢迎的,也许会提供一些帮助,但如果它包括解释“如何”和“为什么”解决问题,那将会大有改进。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人!请编辑您的答案以添加解释,并指出适用的限制和假设。 - Toby Speight

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