【问题标题】:How to tell the active view controller when applicationDidBecomeActive is called?调用 applicationDidBecomeActive 时如何告诉活动视图控制器?
【发布时间】:2012-05-08 16:57:36
【问题描述】:

我觉得我在这里错过了一个技巧......

我只想在调用 applicationDidBecomeActive 时在当前活动视图控制器上调用 viewDidLoad 或 viewDidAppear,这样当应用程序从后台再次启动时,我可以重置一些动画或其他内容。我的一些观点不在乎,但其他人确实需要知道。

我正在使用 Storyboards,并且我的应用程序委托文件具有标准功能 - 但都具有 EMPTY 主体。例如,didFinishLaunchingWithOptions 只返回 YES,不执行任何其他操作。 Storyboard 会自动完成我猜想的所有事情。

那么我怎样才能从我相当空白、无信息的应用委托中与当前视图控制器对话呢?

【问题讨论】:

  • 很可能有一种更简单的方法来执行此操作,但我认为如果您将属性添加到您的应用程序委托 @property (strong, nonatomic)UIViewController *currentViewController.然后每次加载视图时,回调委托以设置该属性。然后在 applicationWillResignActive 中,保存到 NSUserDefaults 并在应用再次激活时检查该值?

标签: ios iphone swift xcode-storyboard


【解决方案1】:

操作系统不会从您的应用代理发送通知,而是自动发送您可以观察到的通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                      selector:@selector(initSongInfo)
                                      name:UIApplicationDidBecomeActiveNotification
                                      object:nil];

当然,请确保在您的 dealloc 方法之前或内部的某个时间停止观察,方法是调用:

[[NSNotificationCenter defaultCenter] removeObserver:self 
                                      name:UIApplicationDidBecomeActiveNotification 
                                      object:nil];

【讨论】:

  • 这是一个比 Brandon Brodjeski 目前接受的答案更好的解决方案。
  • 这是正确的做法
  • 当您正在构建框架并且无法将代码添加到应用程序委托时,这是一种更好的方法。
【解决方案2】:

Swift 版本:

您可以在 viewDidLoad 中添加这一行

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(viewDidBecomeActive), name: UIApplicationDidBecomeActiveNotification, object: nil)

func viewDidBecomeActive(){
    print("viewDidBecomeActive")
}

Swift 5.x 版本

NotificationCenter.default.addObserver(self, selector: #selector(viewDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)

@objc func viewDidBecomeActive() {
    print("viewDidBecomeActive")
}

【讨论】:

  • swift 4 和 5 NotificationCenter.default.addObserver(self, selector: #selector(viewDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
【解决方案3】:

好吧,这真是灾难性的。

你们必须注意事件注册/注销,因为你可能会导致内存泄漏。

要使一切正常运行,您需要设置一个知道注册状态的标志:您是否已登录后台事件。请注意,当用户看到视图控制器(如果他来自其他用户)或者如果他从主屏幕来到您的视图控制器时,您需要注册事件。

当您将视图控制器留给另一个视图控制器时,您还需要取消注册。

简而言之:

斯威夫特 4:

private var registeredToBackgroundEvents = false

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerToBackFromBackground()
}

/// register to back from backround event
private func registerToBackFromBackground() {
    if(!registeredToBackgroundEvents) {
        NotificationCenter.default.addObserver(self, 
        selector: #selector(viewDidBecomeActive), 
        name: UIApplication.didBecomeActiveNotification, object: nil)
        registeredToBackgroundEvents = true
    }
}

/// unregister from back from backround event
private func unregisterFromBackFromBackground() {
    if(registeredToBackgroundEvents) {
        NotificationCenter.default.removeObserver(self, 
        name: UIApplication.didBecomeActiveNotification, object: nil)
        registeredToBackgroundEvents = false
    }

}

@objc func viewDidBecomeActive(){
    logicManager.onBackFromStandby()
}


override func viewWillDisappear(_ animated: Bool) {
    unregisterFromBackFromBackground()
}

【讨论】:

    【解决方案4】:

    您的 AppDelegate 将有一个窗口属性,该窗口将有一个 rootViewController 属性。你可以在这里找到你的 viewController。

    如果你使用的是TabBarController,rootviewcontroller就是tabbarcontroller,你可以调用tabbarcontroller的selectedViewController来获取当前的viewController。

    UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    if ([rootViewController isKindOfClass:[UITabBarController Class]])
        rootViewController = ((UITabBarController *)rootViewController).selectedViewController;
    else if ([rootViewController isKindOfClass:[UINavigationController Class]])
        rootViewController = ((UINavigationController *)rootViewController).topViewController;
    
    [rootViewController viewDidAppear];
    

    如果您有更复杂的带有导航控制器或模式视图的视图层次结构,您可以调用presentedViewController 或topViewController。

    【讨论】:

    • 这个窗口属性对我不起作用,它给了我这个错误:使用未声明的标识符“窗口”。您能否更新答案,因为我真的需要知道屏幕上的视图然后更新它。
    • 感谢您的更新,我更改了它并引发如下异常:unrecognized selector sent to instance :( 对于这行代码:UIViewController *vc = tabbarController.selectedViewController;
    【解决方案5】:

    我建议使用通知。

    在您的应用代理的 applicationdidBecomeActive 方法中输入以下代码:

    [[NSNotificationCenter defaultCenter] postNotificationName:@"appDidBecomeActive" object:nil];
    

    在当前活动视图控制器的 init 方法中订阅通知。

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(updateStuff)        
                                                 name:@"appDidBecomeActive" 
                                               object:nil];
    

    在你的控制器中实现“updateStuff”方法,当应用激活时你应该能够做任何你想做的事情。

    【讨论】:

    • 谢谢,效果很好,似乎是建议中最简洁的方法。虽然我有点担心正确移除观察者。我正在模态地使用一堆 ViewController,因此它们会被大量加载和卸载。我在 -(void)viewDidLoad 中调用了 addObserver,在 -(void)viewDidUnload 中调用了 removeObserver。似乎工作正常。我会进一步测试......
    • 别忘了做 [[NSNotificationCenter defaultCenter] removeObserver:self name:@"appDidBecomeActive" object:nil];在 viewDidUnload
    • 不应该忘记在 dealloc 中删除观察者,因为 viewDidUnload 在许多情况下都不会被调用
    • 我已经测试了两次删除它,冗余删除它很好。出于这个原因,我把它放在 viewDidUnload 和 dealloc 中,我想我已经涵盖了我所有的基础。谢谢大家...
    • 查看 einsteinx2 的答案以获得更优雅的解决方案,使用现有的 UIApplicationDidBecomeActiveNotification 通知。
    【解决方案6】:

    您可以从 AppDelegate 发送一个 NSNotification 并在您的 ViewController 中订阅它,而不是尝试跟踪哪个 ViewController 是当前的。这样视图控制器会跟踪它是否需要调用 viewDidAppear。

    【讨论】:

    • 是的,这就是我所做的。完全有道理,因为我的大多数控制器都不需要注册。
    猜你喜欢
    • 1970-01-01
    • 2011-04-08
    • 2016-10-07
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 2015-07-14
    相关资源
    最近更新 更多