从后台打开应用程序时未调用ViewDidAppear


175

我有一个View Controller,其中我的值为0(标签),当我从另一个视图控制器中打开该View Controller时,ViewController我已设置viewDidAppear为label 设置为20。它可以正常工作,但是当我关闭我的应用程序并再次打开我的应用程序时,该值不会更改,因为viewDidLoadviewDidAppear并且viewWillAppear没有任何调用。打开我的应用程序时该怎么打电话。我需要做些什么applicationDidBecomeActive吗?


您可以在应用程序激活时发布本地通知,并将视图控制器添加为观察者并更新值。
Adil Soomro

Answers:


314

我对事件的确切顺序感到好奇,所以我对应用程序进行了如下检测:(@ Zohaib,您可以使用下面的NSNotificationCenter代码来回答您的问题)。

// AppDelegate.m

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"app will enter foreground");
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"app did become active");
}

// ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"view did load");

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)appDidBecomeActive:(NSNotification *)notification {
    NSLog(@"did become active notification");
}

- (void)appWillEnterForeground:(NSNotification *)notification {
    NSLog(@"will enter foreground notification");
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"view will appear");
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"view did appear");
}

在启动时,输出如下所示:

2013-04-07 09:31:06.505 myapp[15459:11303] view did load
2013-04-07 09:31:06.507 myapp[15459:11303] view will appear
2013-04-07 09:31:06.511 myapp[15459:11303] app did become active
2013-04-07 09:31:06.512 myapp[15459:11303] did become active notification
2013-04-07 09:31:06.517 myapp[15459:11303] view did appear

输入背景,然后重新输入前景:

2013-04-07 09:32:05.923 myapp[15459:11303] app will enter foreground
2013-04-07 09:32:05.924 myapp[15459:11303] will enter foreground notification
2013-04-07 09:32:05.925 myapp[15459:11303] app did become active
2013-04-07 09:32:05.926 myapp[15459:11303] did become active notification

1
Danh,您将UIApplicationWillEnterForegroundNotification映射到appDidEnterForeground:。这不是有点误导吗?注意“将”和“已完成”。那是故意的吗?
Lubiluk 2015年

@Lubiluk-不是故意的。我会编辑。接得好。
丹,2015年

4
这是一个非常有用的答案。我在这里做了一个Swift版本。
Suragch 2015年

完美演示背景模式!
马塞洛·多斯·桑托斯

双击主屏幕按钮并关闭应用程序时,事件的顺序是什么?
Amjad Husseini

134

使用Objective-C

您应该UIApplicationWillEnterForegroundNotificationViewControllerviewDidLoad方法中注册一个,只要应用从后台返回,您就可以在注册通知的方法中做任何您想做的事情。当应用程序从后台返回到前景时,不会调用ViewControllerviewWillAppearviewDidAppear

-(void)viewDidLoad{

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doYourStuff)

  name:UIApplicationWillEnterForegroundNotification object:nil];
}

-(void)doYourStuff{

   // do whatever you want to do when app comes back from background.
}

不要忘记取消注册您的注册通知。

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

请注意,如果您为注册viewControllerUIApplicationDidBecomeActiveNotification则每次您的应用程序激活时都会调用您的方法,不建议注册viewController此通知。

使用Swift

要添加观察者,您可以使用以下代码

 override func viewDidLoad() {
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: "doYourStuff", name: UIApplication.willEnterForegroundNotification, object: nil)
 }

 func doYourStuff(){
     // your code
 }

要删除观察者,您可以使用swift的deinit功能。

deinit {
    NotificationCenter.default.removeObserver(self)
}

4
是的,它是:)有时很难找到答案:)
nsgulliver

@nsgulliver我是否必须手动调用注销注册通知-(void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self]; }。应用程式会帮我做吗?
ios

43

Swift 3.0 ++版本

在您的中viewDidLoad,在通知中心注册以收听此后台操作打开的操作

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

然后添加此功能并执行所需的操作

func doSomething(){
    //...
}

最后,在销毁视图控制器时添加此功能以清理通知观察器。

deinit {
    NotificationCenter.default.removeObserver(self)
}

一种简单而直接的解决方案来处理VC +1中的通知
Mo Zaatar

不能相信这么多其他类似/重复的SO问题都漏掉了这个好答案。
雨果·阿莱克西斯·卡多纳

11

斯威夫特4.2。版

向NotificationCenter注册以在viewDidLoad应用程序从后台返回时收到通知

NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: UIApplication.willEnterForegroundNotification, object: nil)

实现应调用的方法。

@objc private func doSomething() {
    // Do whatever you want, for example update your view.
}

ViewController摧毁后,您可以删除观察者。仅在iOS9和macOS 10.11以下才需要

deinit {
    NotificationCenter.default.removeObserver(self)
}

1
FYI我敢肯定,你不必费心再取出观察,这些天...
Fattie

3

只需让您的视图控制器注册该UIApplicationWillEnterForegroundNotification通知并做出相应反应即可。


我该怎么做?我已经在applicationDidBecomeActive中调用了我的viewController。它重叠viewController还是可以做到这一点?
Zohaib

2
不要在applicationDidBecomeActive中调用viewController(这是错误的,因为它被多次调用了)。注册您viewDidLoad喜欢的@nsgulliver建议通知。您viewDidAppear还将打电话doYourStuff给您的标签设置所需的值。
andreagiavatto

3

我认为注册UIApplicationWillEnterForegroundNotification是冒险的,因为您可能最终会遇到多个控制器对该通知做出反应。当收到通知时,这些控制器仍然可见。

这是我的工作:我直接从应用程序的委托didBecomeActive方法强制在活动控制器上调用viewDidAppear:

将以下代码添加到 - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];

7
如果控制器在viewWillDisappear中而不是在dealloc中为UIApplicationWillEnterForegroundNotification取消注册(应该如此),则可以保证。显式地调用viewDidAppear在我看来就像是骇客,它破坏了语义(个人视图),并且可能使人(根据经验)感到困惑。
joakim 2015年

3

尝试将其添加到AppDelegate applicationWillEnterForeground中。

func applicationWillEnterForeground(_ application: UIApplication) {        
    // makes viewWillAppear run
    self.window?.rootViewController?.beginAppearanceTransition(true, animated: false)
    self.window?.rootViewController?.endAppearanceTransition()
}

2

根据Apple的文档:

(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated;

说明:
告诉子控制器其外观即将更改。如果要实现自定义容器控制器,请使用此方法告诉子项其视图即将出现或消失不要调用viewWillAppear:viewWillDisappear:viewDidAppear:,或viewDidDisappear:直接

(void)endAppearanceTransition;

描述:

告诉子控制器其外观已更改。如果要实现自定义容器控制器,请使用此方法告诉子视图转换已完成。

样例代码:

(void)applicationDidEnterBackground:(UIApplication *)application
{

    [self.window.rootViewController beginAppearanceTransition: NO animated: NO];  // I commented this line

    [self.window.rootViewController endAppearanceTransition]; // I commented this line

}

问题:我如何解决?

:我发现这条线在应用中。这些行使我的应用程序未收到任何ViewWillAppear通知。当我评论这些行时,它工作正常

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.