ViewDidAppear non viene chiamato quando si apre l'app dallo sfondo


175

Ho un View Controller in cui il mio valore è 0 (etichetta) e quando apro quel View Controller da un altro ViewControllerho viewDidAppearimpostato il valore 20 sull'etichetta. Funziona bene, ma quando chiudo la mia app e che ancora una volta ho aperto la mia app, ma il valore non cambia perché viewDidLoad, viewDidAppeare viewWillAppearnon vieni chiamato. Come posso chiamare quando apro la mia app. Devo fare qualcosa da applicationDidBecomeActive?


È possibile pubblicare una notifica locale quando l'applicazione diventa attiva e aggiungere il controller di visualizzazione come osservatore e aggiornare i valori.
Adil Soomro,

Risposte:


314

Curioso dell'esatta sequenza di eventi, ho strumentato un'app come segue: (@Zohaib, puoi utilizzare il codice NSNotificationCenter di seguito per rispondere alla tua domanda).

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

Al lancio, l'output è simile al seguente:

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

Immettere lo sfondo, quindi rientrare in primo piano:

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
Danh, hai mappato UIApplicationWillEnterForegroundNotification su appDidEnterForeground :. Non è un po 'fuorviante? Notare "will" e "did". Era intenzionale?
Lubiluk,

@Lubiluk - non intenzionale. Lo modificherò. Buona pesca.
danh,

4
Questa è stata una risposta molto utile. Ne ho fatto una versione Swift qui .
Suragch,

Dimostrazione perfetta della modalità background!
Marcelo dos Santos,

Quali sono la sequenza di eventi quando si tocca due volte il tasto Home e si chiude l'app?
Amjad Husseini,

134

Utilizzando Objective-C

Si dovrebbe registrare un UIApplicationWillEnterForegroundNotificationin ViewController's viewDidLoadmetodo e ogni volta che un'applicazione torna dal fondo si può fare quello che vuoi fare nel metodo registrati per la notifica. ViewController's viewWillAppear o viewDidAppear non saranno chiamati quando applicazione torna da sfondo al primo piano.

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

Non dimenticare di annullare la registrazione della notifica per cui sei registrato.

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

Nota se ti registri viewControllerper UIApplicationDidBecomeActiveNotificationallora il tuo metodo verrebbe chiamato ogni volta che la tua app diventa attiva, non è consigliabile registrarsi viewControllerper questa notifica.

Usando Swift

Per aggiungere l'osservatore puoi usare il seguente codice

 override func viewDidLoad() {
    super.viewDidLoad()

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

 func doYourStuff(){
     // your code
 }

Per rimuovere l'osservatore puoi usare la funzione deinit di swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}

4
Sì, lo è :) a volte è difficile trovare le risposte :)
nsgulliver

@nsgulliver Devo invocare manualmente annullare la registrazione della notifica - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. L'app lo farà per me?
iOS

43

Swift 3.0 ++ versione

Nel tuo viewDidLoad, registrati al centro notifiche per ascoltare questo aperto dall'azione in background

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

Quindi aggiungere questa funzione ed eseguire l'azione necessaria

func doSomething(){
    //...
}

Infine aggiungi questa funzione per ripulire l'osservatore delle notifiche quando il controller della vista viene distrutto.

deinit {
    NotificationCenter.default.removeObserver(self)
}

Soluzione semplice e diretta per gestire la notifica all'interno del VC +1
Mo Zaatar

Non riesco a credere che questa bella risposta sia mancata in così tante altre domande SO simili / duplicate.
Hugo Allexis Cardona,

11

Rapido 4.2. versione

Registrati con NotificationCenter viewDidLoadper ricevere una notifica quando l'app torna dallo sfondo

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

Implementare il metodo che dovrebbe essere chiamato.

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

Puoi rimuovere l'osservatore una volta ViewControllerdistrutto. Questo è richiesto solo sotto iOS9 e macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}

1
FYI Sono abbastanza sicuro che non devi più preoccuparti di rimuovere gli osservatori in questi giorni ...
Fattie

3

Devi solo far registrare il tuo controller di visualizzazione per la UIApplicationWillEnterForegroundNotificationnotifica e reagire di conseguenza.


Come lo farò? ho chiamato il mio viewController in applicationDidBecomeActive ma. si sovrappone a ViewController o va bene farlo?
Zohaib,

2
Non chiamare viewController in applicationDidBecomeActive (che comunque è sbagliato perché viene chiamato più volte). Registrati per la notifica nel tuo viewDidLoadlike @nsgulliver suggerito. Chiamerai viewDidAppearanche doYourStuffper impostare l'etichetta con il valore desiderato.
andreagiavatto

3

Penso che registrarsi per UIApplicationWillEnterForegroundNotification sia rischioso in quanto potresti finire con più di un controller che reagisce a tale notifica. Nulla garantisce che questi controller siano ancora visibili alla ricezione della notifica.

Ecco cosa faccio: imposto viewDidAppear di chiamata sul controller attivo direttamente dal metodo didBecomeActive delegato dell'app:

Aggiungi il codice qui sotto a - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];

7
È garantito se il controller annulla la registrazione (come dovrebbe) per UIApplicationWillEnterForegroundNotification in viewWillDisappear anziché in dealloc. Chiamare viewDidAppear mi sembra esplicitamente un hack, rompe la semantica (vista personale) e può confondere le persone (per esperienza).
Joakim,

3

prova ad aggiungere questo in AppDelegate applicationWillEnterForeground.

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

2

Secondo la documentazione di Apple:

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

Descrizione:
indica a un controller figlio che il suo aspetto sta per cambiare. Se stai implementando un controller contenitore personalizzato, utilizza questo metodo per dire al figlio che le sue viste stanno per apparire o scomparire . Non invocare viewWillAppear:, viewWillDisappear:, viewDidAppear:, o viewDidDisappear:direttamente .

(void)endAppearanceTransition;

Descrizione:

Indica a un controller figlio che il suo aspetto è cambiato. Se si sta implementando un controller contenitore personalizzato, utilizzare questo metodo per comunicare al figlio che la transizione della vista è completa.

Codice di esempio:

(void)applicationDidEnterBackground:(UIApplication *)application
{

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

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

}

Domanda: come ho risolto?

Ans : Ho trovato questo pezzo di linee nell'applicazione. Questa riga ha fatto in modo che la mia app non ricevesse alcuna notifica ViewWillAppear. Quando ho commentato queste righe funziona bene .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.