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

Posted

技术标签:

【中文标题】从后台打开应用程序时不调用 ViewDidAppear【英文标题】:ViewDidAppear is not called when opening app from background 【发布时间】:2013-03-29 15:57:44 【问题描述】:

我有一个视图控制器,其中我的值为 0(标签),当我从另一个 ViewController 打开该视图控制器时,我已将 viewDidAppear 设置为标签上的值 20。它工作正常,但是当我关闭我的应用程序并再次打开我的应用程序但值没有改变,因为viewDidLoadviewDidAppearviewWillAppear 没有被调用。打开我的应用程序时如何拨打电话。我必须从applicationDidBecomeActive 做任何事情吗?

【问题讨论】:

您可以在应用程序激活时发布本地通知,并将您的视图控制器添加为观察者并更新值。 【参考方案1】:

对事件的确切顺序感到好奇,我按如下方式检测了一个应用程序:(@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

【讨论】:

Danh,您将 UIApplicationWillEnterForegroundNotification 映射到 appDidEnterForeground:。这不是有点误导吗?注意“将”和“做了”。这是故意的吗? @Lubiluk - 不是故意的。我会编辑。很好的收获。 这是一个非常有用的答案。我制作了它的 Swift 版本here。 后台模式完美演示! 双击主页按钮并关闭应用程序的事件顺序是什么?【参考方案2】:

使用 Objective-C

您应该在您的ViewControllerviewDidLoad 方法中注册一个UIApplicationWillEnterForegroundNotification,并且每当应用程序从后台返回时,您可以在注册通知的方法中做任何您想做的事情。 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];

注意如果您将viewController注册为UIApplicationDidBecomeActiveNotification,那么每次您的应用激活时都会调用您的方法,不建议注册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)

【讨论】:

是的 :) 有时很难找到答案 :) @nsgulliver 我是否必须手动调用取消注册通知 -(void)dealloc [[NSNotificationCenter defaultCenter] removeObserver:self]; 。应用会为我做吗?【参考方案3】:

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 中处理通知的简单直接的解决方案 不敢相信在许多其他类似/重复的 SO 问题中都错过了这个好答案。【参考方案4】:

斯威夫特 4.2。版本

viewDidLoad注册NotificationCenter,当应用从后台返回时收到通知

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)

【讨论】:

仅供参考,我很确定这些天你不需要再为移除观察者而烦恼了......【参考方案5】:

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

【讨论】:

我该怎么做?我已经在 applicationDidBecomeActive 中调用了我的 viewController,但是。它与 viewController 重叠还是可以这样做? 不要在 applicationDidBecomeActive 中调用你的 viewController (这是错误的,因为它被多次调用)。在@nsgulliver 建议的viewDidLoad 中注册通知。您的 viewDidAppear 还将调用 doYourStuff 以将您的标签设置为所需的值。【参考方案6】:

我认为注册 UIApplicationWillEnterForegroundNotification 是有风险的,因为您最终可能会有多个控制器对该通知做出反应。无法保证这些控制器在收到通知时仍然可见。

这是我要做的:我直接从 App 的委托 didBecomeActive 方法强制在活动控制器上调用 viewDidAppear:

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

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

[activeController viewDidAppear:NO];

【讨论】:

如果控制器在 viewWillDisappear 中而不是在 dealloc 中取消注册 UIApplicationWillEnterForegroundNotification,则可以保证。显式调用 viewDidAppear 对我来说就像是一种 hack,它会破坏语义(个人观点)并且会混淆人们(根据经验)。【参考方案7】:

尝试在 AppDelegate applicationWillEnterForeground 中添加它。

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

【讨论】:

【参考方案8】:

根据 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


问题:我是如何解决的?

Ans:我在应用程序中发现了这条线。这些行使我的应用程序没有收到任何 ViewWillAppear 通知。 当我评论这些行时,它运行良好

【讨论】:

以上是关于从后台打开应用程序时不调用 ViewDidAppear的主要内容,如果未能解决你的问题,请参考以下文章

从后台弹出时不调用 Fragment 的 onResume()

应用程序在后台时不调用 AFHTTPSessionManager 块

onMessageReceived(RemoteMessage remoteMessage) 应用程序在后台或被杀死时不调用

Firebase onMessageReceived(RemoteMessage remoteMessage),当应用程序在后台时不被调用[重复]

苹果手机怎么设置后台运行时不自动关闭?

iOS:调用 AppDelegate 的打开 url 时不显示 Touch Id