11

こんにちは。ローカル通知を使用してアプリを開くと、UIの更新と内部ステータスの変更で応答するアプリを作成しています。ストーリーボードを使用しており、ステータスの変化を監視するためにメインビューコントローラーを設定しました。

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

私のアプリデリゲートにはこれがあります:

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

そして、これは問題なく機能します。アプリがバックグラウンドで実行されている場合、View Controllerは通知をインターセプトし、それに応じて反応します。(アプリがフォアグラウンドで実行されている場合、UIが直接処理されるため、無視されます。)

この問題は、アプリが強制終了され、通知を受信したときに発生します。私はこれをdidFinishLaunchingWithOptionsメソッドで記述し、電話をクイックデバッグテクニックとして振動させます:)、そして通知を受け取ります:

- (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;
}

電話は振動するので通知はありますが、オブザーバーをトリガーするようには見えません。これは、ビューコントローラのdidViewLoadメソッドがまだ呼び出されていないためだと思います。これを回避する方法がわかりません。UIStoryboardのinstantiateViewControllerWithIdentifier:メソッドを使用して、View Controllerが実際に存在することを確認できると思いますが、ストーリーボード自体のライフサイクルによって最終的にインスタンス化されるインスタンスに加えて、その「余分な」インスタンスを取得することはありません。 ?クラスリファレンスドキュメントの内容から判断すると、この種のことを行うことを正確に意図しているわけではありません。

ここで非常に明白な何かが欠けていますか?実際、私のアプローチはこの種の状況に適していますか?

ありがとう!

4

1 に答える 1

12

ビューコントローラは、何かがビューを要求するまでビューをロードしません。起動時には、通常、application:didFinishLaunchingWithOptions:返品後に発生します。

なぜだろうと思うかもしれません。答えは、起動時にいくつかのView Controllerをインスタンス化する可能性があり、そのうちのいくつかは非表示になっているということです。たとえば、ウィンドウのルートビューコントローラーがであるUINavigationController場合、ナビゲーションコントローラーにビューコントローラーのスタック(ユーザーがアプリを最後に実行したときにプッシュしたスタック)をロードできます。このスタックの最上位のViewControllerのみが表示されるため、他のViewControllerのビューをロードする必要はありません。application:didFinishLaunchingWithOptions:システムは、必要なビューのみがロードされるように、ビューをロードする前に戻るまで待機します。

したがって、問題を回避する1つの方法は、ビューコントローラにビューを要求し、強制的にロードすることです。ビューコントローラがウィンドウのルートビューコントローラである場合は、次のように実行できます。

- (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;
}

別の回避策は、ViewControllerのinitWithCoder:メソッドで通知の監視を開始することです。

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

これは、メッセージの前に発生するMainStoryboardからViewControllerがインスタンス化されるときに呼び出されapplication:didFinishLaunchingWithOptions:ます。

于 2013-02-10T20:03:56.433 に答える