草庐IT

ios - 应用程序 :didFinishLaunchingWithOptions: firing notification before destination controller is created

coder 2023-07-28 原文

您好, 我正在编写一个应用程序,当使用本地通知打开它时,它应该响应 UI 更新和内部状态更改。我正在使用 Storyboard,我已经设置了我的主视图 Controller 来观察状态变化:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeByNotification:) name:@"Resume" object:nil];
}

在我的应用委托(delegate)中,我有这个:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    if (application.applicationState == UIApplicationStateInactive)
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"Resume" object:self userInfo:notification.userInfo];
    }
}

这工作得很好:如果应用程序在后台运行, View Controller 将拦截通知并做出相应的 react 。 (如果应用程序在前台运行,它会被忽略,因为 UI 正在被直接处理。)

当应用程序被终止并收到通知时,就会出现问题。我在 didFinishLaunchingWithOptions 方法中写了这个,让手机振 Action 为一种快速调试技术:),我确实收到了通知:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UILocalNotification *localNotification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (localNotification)
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"Resume" object:self userInfo:localNotification.userInfo];
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    }

    return YES;
}

手机确实会振动,所以通知就在那里,但它似乎并没有触发观察者。我想这是因为尚未调用 View Controller 的 didViewLoad 方法。我不确定如何解决这个问题。我想我可以使用 UIStoryboard 的 instantiateViewControllerWithIdentifier: 方法来确保 View Controller 确实存在,但除了最终将由 Storyboard 自己的生命周期实例化的实例之外,我不会得到它的“额外”实例吗?从类引用文档上的内容来看,它并不完全是为了做这种事情。

我是否遗漏了一些非常明显的东西?事实上,对于这种情况,我的方法是否正确?

谢谢!

最佳答案

View Controller 不会加载它的 View ,直到有东西请求它的 View 。在启动时,这通常发生在 application:didFinishLaunchingWithOptions: 返回之后。

你可能想知道为什么。答案是您可能会在启动时实例化多个 View Controller ,其中一些是隐藏的。例如,如果您的窗口的 Root View Controller 是一个 UINavigationController,您可以使用一堆 View Controller (用户上次应用程序运行时推送的堆栈)加载导航 Controller 。只有这个堆栈的顶 View Controller 是可见的,所以不需要加载其他 View Controller 的 View 。系统会等到 application:didFinishLaunchingWithOptions: 在加载任何 View 之前返回,以便只加载必要的 View 。

因此,解决您的问题的一种方法就是简单地向 View Controller 询问其 View ,从而强制加载它。如果您的 View Controller 是窗口的 Root View Controller ,您可以这样做:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UILocalNotification *localNotification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (localNotification) {
        [[self.window rootViewController] view];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"Resume" object:self userInfo:localNotification.userInfo];
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    }

    return YES;
}

另一种解决方法是在 View Controller 的 initWithCoder: 方法中开始观察通知:

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeByNotification:) name:@"Resume" object:nil];
    }
    return self;
}

当 View Controller 从 MainStoryboard 实例化时调用,这发生在 application:didFinishLaunchingWithOptions: 消息之前。

关于ios - 应用程序 :didFinishLaunchingWithOptions: firing notification before destination controller is created,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14801889/

有关ios - 应用程序 :didFinishLaunchingWithOptions: firing notification before destination controller is created的更多相关文章

随机推荐