バックグラウンドからアプリを開くときにViewDidAppearが呼び出されない


175

値が0(ラベル)のビューコントローラーがあり、別のビューコントローラーからそのビューコントローラーを開くと、ラベルに値20をViewController設定viewDidAppearするように設定しました。これは、罰金に動作しますが、私は私のアプリを閉じていないと、再び、私は私のアプリを開くよりも、その値があるため変化しない場合viewDidLoadviewDidAppearおよびviewWillAppear何も呼び出されます。アプリを開いたときにどのように呼び出すことができますか?から何かをする必要がありapplicationDidBecomeActiveますか?


アプリケーションがアクティブになったときにローカル通知をポストし、ビューコントローラーをオブザーバーとして追加して値を更新できます。
Adil Soomro 2013

回答:


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
ダン、UIApplicationWillEnterForegroundNotificationをappDidEnterForeground:にマッピングしました。それは少し誤解を招くではありませんか?「する」と「した」に注意してください。それは意図的なものでしたか?
Lubiluk、2015

@Lubiluk-意図的ではありません。編集します。良いキャッチ。
danh 2015

4
これは非常に役立つ回答でした。ここで Swiftバージョンを作成しました
Suragch

バックグラウンドモードの完全なデモンストレーション!
マルセロドスサントス

ホームボタンをダブルタップしてアプリを閉じたときのイベントのシーケンスは何ですか?
Amjad Husseini 2017年

134

Objective-Cの使用

のメソッドにを登録する必要UIApplicationWillEnterForegroundNotificationがあります。バックグラウンドからアプリが戻ってきたときはいつでも、通知用に登録されたメソッドでやりたいことをすべて実行できます。のviewWillAppearまたはviewDidAppearは、アプリがバックグラウンドからフォアグラウンドに戻ったときに呼び出されません。ViewControllerviewDidLoadViewController

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

4
はい、そうです:)答えを見つけるのが難しい場合があります:)
nsgulliver 2013

@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の質問で見逃されているとは信じられません。
Hugo Allexis Cardona 2018

11

Swift 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)
}

1
ちなみに、最近はオブザーバーを削除する手間が省けると確信しています...
Fattie

3

ビューコントローラーにUIApplicationWillEnterForegroundNotification通知を登録させ、それに応じて反応させるだけです。


どうすればいいですか?applicationDidBecomeActiveで自分のviewControllerを呼び出しましたが、それはviewControllerまたはそれを行うにはその罰金と重なりますか?
Zohaib 2013

2
applicationDidBecomeActiveでviewControllerを呼び出さないでください(複数回呼び出されるため、とにかく間違っています)。viewDidLoadLike @nsgulliverが提案する通知に登録してください。あなたviewDidAppearも呼ぶdoYourStuff希望の値を使用してラベルを設定します。
andreagiavatto 2013

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
コントローラーがdeallocではなくviewWillDisappearで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通知を受け取りませんでした。私がこれらの行にコメントしたとき、それはうまくいきます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.