ViewDidAppear wird beim Öffnen der App aus dem Hintergrund nicht aufgerufen

175

Ich habe einen View Controller, in dem mein Wert 0 (Beschriftung) ist, und wenn ich diesen View Controller von einem anderen aus öffne, habe ViewControllerich viewDidAppearden Wert 20 auf dem Etikett festgelegt. Es funktioniert gut , aber wenn ich meine App zu schließen und als ich wieder meine app öffnen , aber der Wert ändert sich nicht , weil viewDidLoad, viewDidAppearund viewWillAppearnichts aufgerufen. Wie kann ich anrufen, wenn ich meine App öffne? Muss ich etwas tun applicationDidBecomeActive?

Zohaib
quelle
Sie können eine lokale Benachrichtigung veröffentlichen, wenn die Anwendung aktiv wird, und Ihren Ansichts-Controller als Beobachter hinzufügen und Werte aktualisieren.
Adil Soomro

Antworten:

314

Ich war neugierig auf die genaue Abfolge der Ereignisse und habe eine App wie folgt instrumentiert: (@Zohaib, Sie können den folgenden NSNotificationCenter-Code verwenden, um Ihre Frage zu beantworten.)

// 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");
}

Beim Start sieht die Ausgabe folgendermaßen aus:

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

Geben Sie den Hintergrund ein und geben Sie den Vordergrund erneut ein:

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
quelle
1
Danh, Sie haben UIApplicationWillEnterForegroundNotification appDidEnterForeground: zugeordnet. Ist das nicht ein bisschen irreführend? Beachten Sie "wird" und "tat". War das beabsichtigt?
Lubiluk
@Lubiluk - nicht beabsichtigt. Ich werde bearbeiten. Guter Fang.
Danh
4
Dies war eine sehr nützliche Antwort. Ich habe eine Swift - Version davon hier .
Suragch
Perfekte Demonstration des Hintergrundmodus!
Marcelo dos Santos
Wie ist die Reihenfolge der Ereignisse, wenn Sie zweimal auf die Home-Schaltfläche tippen und die App schließen?
Amjad Husseini
134

Verwenden von Objective-C

Sie sollen ein Register UIApplicationWillEnterForegroundNotificationin Ihrer ViewController‚s viewDidLoadMethode und wann immer app zurück von Hintergrund kommt können Sie tun , was Sie in der Methode für die Benachrichtigung registriert tun wollen. ViewController‚s viewWillAppear oder viewDidAppear wird nicht aufgerufen werden , wenn app zurück von Hintergrund in den Vordergrund kommt.

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

Vergessen Sie nicht, die Registrierung der Registrierung aufzuheben, für die Sie registriert sind.

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Hinweis: Wenn Sie sich viewControllerfür registrieren, wird Ihre UIApplicationDidBecomeActiveNotificationMethode jedes Mal aufgerufen, wenn Ihre App aktiv wird. Es wird nicht empfohlen, sich viewControllerfür diese Benachrichtigung zu registrieren .

Swift verwenden

Zum Hinzufügen eines Beobachters können Sie den folgenden Code verwenden

 override func viewDidLoad() {
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: "doYourStuff", name: UIApplication.willEnterForegroundNotification, object: nil)
 }

 func doYourStuff(){
     // your code
 }

Um den Beobachter zu entfernen, können Sie die Deinit-Funktion von Swift verwenden.

deinit {
    NotificationCenter.default.removeObserver(self)
}
nsgulliver
quelle
4
Ja, das ist es :) Manchmal ist es schwierig, Antworten zu finden :)
nsgulliver
@nsgulliver Muss ich die Benachrichtigung manuell aufheben, um die Registrierung aufzuheben - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. Wird die App das für mich tun?
ios
43

Swift 3.0 ++ Version

viewDidLoadRegistrieren Sie sich in Ihrem Benachrichtigungscenter, um diese im Hintergrund geöffnete Aktion anzuhören

NotificationCenter.default.addObserver(self, selector:#selector(doSomething), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
        

Fügen Sie dann diese Funktion hinzu und führen Sie die erforderliche Aktion aus

func doSomething(){
    //...
}

Fügen Sie schließlich diese Funktion hinzu, um den Benachrichtigungsbeobachter zu bereinigen, wenn Ihr View Controller zerstört wird.

deinit {
    NotificationCenter.default.removeObserver(self)
}
Fangming
quelle
Einfache und unkomplizierte Lösung für die Benachrichtigung innerhalb des VC +1
Mo Zaatar
Ich kann nicht glauben, dass diese nette Antwort in so vielen anderen ähnlichen / doppelten SO-Fragen übersehen wird.
Hugo Allexis Cardona
11

Swift 4.2. Ausführung

Registrieren Sie sich beim NotificationCenter viewDidLoad, um benachrichtigt zu werden, wenn die App aus dem Hintergrund zurückkehrt

NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: UIApplication.willEnterForegroundNotification, object: nil)

Implementieren Sie die Methode, die aufgerufen werden soll.

@objc private func doSomething() {
    // Do whatever you want, for example update your view.
}

Sie können den Beobachter entfernen, sobald der ViewControllerzerstört ist. Dies ist nur unter iOS9 und macOS 10.11 erforderlich

deinit {
    NotificationCenter.default.removeObserver(self)
}
gebirgsbärbel
quelle
1
Zu Ihrer Information Ich bin mir ziemlich sicher, dass Sie sich heutzutage nicht mehr die Mühe machen müssen, Beobachter zu entfernen ...
Fattie
3

Lassen Sie einfach Ihren View Controller für die UIApplicationWillEnterForegroundNotificationBenachrichtigung registrieren und reagieren Sie entsprechend.

andreagiavatto
quelle
Wie mache ich das? Ich habe meinen viewController in applicationDidBecomeActive aber aufgerufen. es überlappt viewController oder ist es in Ordnung, das zu tun?
Zohaib
2
Rufen Sie Ihren viewController nicht in applicationDidBecomeActive auf (was sowieso falsch ist, weil es mehrmals aufgerufen wird). Registrieren Sie sich für die Benachrichtigung in Ihrem viewDidLoadvorgeschlagenen @nsgulliver. Sie viewDidAppearwerden auch anrufen doYourStuff, um Ihr Etikett auf den gewünschten Wert einzustellen.
andreagiavatto
3

Ich denke, die Registrierung für die UIApplicationWillEnterForegroundNotification ist riskant, da möglicherweise mehr als ein Controller auf diese Benachrichtigung reagiert. Nichts garantiert, dass diese Controller beim Empfang der Benachrichtigung noch sichtbar sind.

Folgendes mache ich: Ich erzwinge den Aufruf von viewDidAppear auf dem aktiven Controller direkt von der didBecomeActive-Methode des App-Delegaten:

Fügen Sie den folgenden Code hinzu - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];
Erwan
quelle
7
Es ist garantiert, wenn der Controller die Registrierung für die UIApplicationWillEnterForegroundNotification in viewWillDisappear anstatt in dealloc aufhebt (wie es sollte). Das Aufrufen von viewDidAppear sieht für mich explizit wie ein Hack aus, es bricht die Semantik (persönliche Ansicht) und kann Menschen (aus Erfahrung) verwirren.
Joakim
3

Versuchen Sie, dies in AppDelegate applicationWillEnterForeground hinzuzufügen.

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

Gemäß Apples Dokumentation:

(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated;

Beschreibung:
Sagt einem untergeordneten Controller, dass sich sein Erscheinungsbild ändern wird. Wenn Sie einen benutzerdefinierten Container-Controller implementieren, teilen Sie dem Kind mit dieser Methode mit, dass seine Ansichten angezeigt oder ausgeblendet werden . Sie nicht aufrufen viewWillAppear:, viewWillDisappear:, viewDidAppear:, oder viewDidDisappear:direkt .

(void)endAppearanceTransition;

Beschreibung:

Teilt einem untergeordneten Controller mit, dass sich sein Erscheinungsbild geändert hat. Wenn Sie einen benutzerdefinierten Container-Controller implementieren, teilen Sie dem Kind mit dieser Methode mit, dass der Ansichtsübergang abgeschlossen ist.

Beispielcode:

(void)applicationDidEnterBackground:(UIApplication *)application
{

    [self.window.rootViewController beginAppearanceTransition: NO animated: NO];  // I commented this line

    [self.window.rootViewController endAppearanceTransition]; // I commented this line

}

Frage: Wie habe ich behoben?

Antwort : Ich habe diese Zeilen in der Anwendung gefunden. Diese Zeilen haben dazu geführt, dass meine App keine ViewWillAppear-Benachrichtigungen erhalten hat. Als ich diese Zeilen kommentierte, funktionierte es gut .

Lakshmi
quelle