如何从 AppDelegate 访问 ViewController 变量

Posted

技术标签:

【中文标题】如何从 AppDelegate 访问 ViewController 变量【英文标题】:How to access ViewController variable from AppDelegate 【发布时间】:2017-02-20 16:59:58 【问题描述】:

我有一个 ViewController 叫做:ViewController 我有一个名为 AppDelegate 的 AppDelegate

它们不是以编程方式制作的,它们与您在 swift 中创建新应用时一样默认。

想象一下我在 ViewController 中有:

class ViewController: UIViewController 

  var animal = "dog" 


例如,我想在应用程序进入后台时打印动物值。所以在 AppDelegate 我有:

func applicationDidEnterBackground(_ application: UIApplication) 

    var ViewController: ViewController!

    print("animal = \(myViewController.animal)")   


我得到:致命错误:在展开可选值时意外发现 nil

如何从我的 AppDelegate 访问该值? PS:我试过google/***的前2页

【问题讨论】:

这一行var ViewController: ViewController!必须是var controller = ViewController(),然后是print("animal = \(controller.animal)") @ReinierMelian 不,这是错误的,因为它只是创建了一个新的视图控制器并且没有引用现有的控制器。 好吧@rmaddy 我知道这不是最好的方法,但我试图解释他需要的想法是在他的 ViewController 类中打印一个静态值 @ReinierMelian 但它非常具有误导性。您使解决方案看起来像是创建视图控制器的新实例。这根本不是真的。 【参考方案1】:

你需要获取 rootViewController

func applicationDidEnterBackground(_ application: UIApplication) 

    let viewController = self.window?.rootViewController as? ViewController
    print(viewController?.animal)


【讨论】:

你真的应该避免所有这些!(崩溃运算符)。 为什么你只删除了! 之一而不是两个? @rmaddy 所以将已经初始化的rootViewController 转换为ViewController 与仅仅初始化 到ViewController 不同吗? @Honey 当然,这个答案假定应用程序的根控制器是所需的视图控制器。如果有问题的视图控制器在视图层次结构中更靠后,则可能需要调整此代码。 @Honey 不,不是。我所说的正是我的意思。我不知道所需的视图控制器是否是根视图控制器。这是这个答案提出的,不是我提出的。【参考方案2】:

您可以在AppDelegate 中获得rootViewController,但您无法确定在进入后台时是否是可见视图控制器,您可能最终会遇到另一个ViewController

实现所需功能的最佳方法是在 ViewController 中添加函数并为 UIApplicationDidEnterBackground 通知分配观察者

当控制器被取消初始化时,你需要移除观察者

有点像

override func viewDidLoad() 
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, 
    selector: #selector(applicationDidEnterBackground), 
    name: NSNotification.Name.UIApplicationDidEnterBackground, 
    object: nil)    


deinit 
    NotificationCenter.default.removeObserver(self)


func applicationDidEnterBackground() 
    //do something here
    print("animal: \(animal)")

【讨论】:

这可能是 OP 想要做的最好的方法。但是,一个好的答案将首先解释问题中的代码有什么问题,然后解释如何修复它。然后一个很好的答案会在此之后提供更好的替代解决方案。 并且使用viewWillAppear/Disappear 可能不是添加/删除观察者的最佳选择。如果此视图控制器已推送或呈现另一个视图控制器,那么当应用程序进入后台时,此代码将不会显示消息。这可能是也可能不是期望的行为。 @rmaddy 谢谢你的反馈我编辑了我的答案【参考方案3】:

所有选项都从nil 开始——除非您初始化它们或将它们的默认值设置为其他值。现在,问问自己我在哪里初始化了我的 ViewController 实例?好吧,你没有!

var ViewController: ViewController! 

上面的行仅表示 ViewController 是 of 类型 ViewController,尽管它从一开始也未包装(尽管仍未初始化)。

var ViewController = ViewController()

现在这一行意味着 ViewController 已初始化,并带有 ViewController initializer。看到=?请参阅()() 就像 do/initialize 这个。

所以错误告诉你的是,你正在向它发送消息,但它仍然是nil。如果你初始化它,那么你就可以访问它的属性。

话虽如此,这不会在视觉上呈现新实例化的 viewController。为此,您必须执行以下操作:

let vc = ViewController()
self.window?.rootViewController = vc

但正如 rmaddy 在 cmets 中提到的那样,这是一个坏主意。另一种方法是简单地将现有的 rootViewControllercast 转换为 ViewController。

let viewController = self.window?.rootViewController as? ViewController

记住要投射你必须使用as?(安全投射)或as!(强制投射)

【讨论】:

但是 OP 想要引用现有的视图控制器,而不是创建一个新的实例。 为什么你的更新提到了更改根视图控制器的代码? OP 想要显示现有视图控制器的现有值。建议一种解决方案是创建一个新的视图控制器并使其成为应用程序的根视图控制器是不合时宜的。 @rmaddy 我认为 OP(有 120 个代表)不太了解这种方法,这只是需要考虑/学习的东西 但是每次应用程序进入后台时用新的根视图控制器替换现有根视图控制器的建议是如何在应用程序中显示某些现有视图控制器的属性的正确解决方案? @rmaddy 我明白你的意思,这很糟糕。 :D。谢谢你把所有的cmets和解释一下。

以上是关于如何从 AppDelegate 访问 ViewController 变量的主要内容,如果未能解决你的问题,请参考以下文章

如何从 AppDelegate 访问 ViewController 变量

如何从 appdelegate 访问 uitablviews 选定项目?

如何从 appDelegate 访问每个 ViewController?

从AppDelegate中访问NavigationController指向的初始视图

Swift:如何通过快速操作从 AppDelegate 访问某个 TabBar 选项卡?

如果它在 TabBarController 中,如何从 AppDelegate 访问 ViewController 的属性?