从后台打开应用程序时不调用 ViewDidAppear
Posted
技术标签:
【中文标题】从后台打开应用程序时不调用 ViewDidAppear【英文标题】:ViewDidAppear is not called when opening app from background 【发布时间】:2013-03-29 15:57:44 【问题描述】:我有一个视图控制器,其中我的值为 0(标签),当我从另一个 ViewController
打开该视图控制器时,我已将 viewDidAppear
设置为标签上的值 20。它工作正常,但是当我关闭我的应用程序并再次打开我的应用程序但值没有改变,因为viewDidLoad
、viewDidAppear
和viewWillAppear
没有被调用。打开我的应用程序时如何拨打电话。我必须从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
您应该在您的ViewController
的viewDidLoad
方法中注册一个UIApplicationWillEnterForegroundNotification
,并且每当应用程序从后台返回时,您可以在注册通知的方法中做任何您想做的事情。 ViewController
的 viewWillAppear 或 viewDidAppear 在应用从后台返回到前台时不会被调用。
-(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),当应用程序在后台时不被调用[重复]