ViewDidAppear n'est pas appelé lors de l'ouverture de l'application en arrière-plan

176

J'ai un contrôleur de vue dans lequel ma valeur est 0 (étiquette) et lorsque j'ouvre ce contrôleur de vue à partir d'un autre, ViewControllerj'ai viewDidAppeardéfini la valeur 20 sur l'étiquette. Il fonctionne très bien , mais quand je ferme mon application et que de nouveau j'ouvrir mon application , mais la valeur ne change pas parce que viewDidLoad, viewDidAppearet viewWillAppearrien ne s'appelle. Comment puis-je appeler lorsque j'ouvre mon application. Dois-je faire quelque chose à partir de applicationDidBecomeActive?

Zohaib
la source
Vous pouvez publier une notification locale lorsque l'application devient active et ajouter votre contrôleur de vue en tant qu'observateur et mettre à jour les valeurs.
Adil Soomro

Réponses:

314

Curieux de connaître la séquence exacte des événements, j'ai instrumenté une application comme suit: (@Zohaib, vous pouvez utiliser le code NSNotificationCenter ci-dessous pour répondre à votre question).

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

Au lancement, la sortie ressemble à ceci:

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

Entrez l'arrière-plan puis entrez à nouveau au premier plan:

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
la source
1
Danh, vous avez mappé UIApplicationWillEnterForegroundNotification à appDidEnterForeground :. N'est-ce pas un peu trompeur? Remarquez "will" et "did". Était-ce intentionnel?
Lubiluk
@Lubiluk - pas intentionnel. Je vais éditer. Bonne prise.
danh
4
C'était une réponse très utile. J'en ai fait une version Swift ici .
Suragch
Démonstration parfaite du mode de fond!
Marcelo dos Santos
Quelle est la séquence d'événements lorsque vous appuyez deux fois sur le bouton d'accueil et fermez l'application?
Amjad Husseini
134

Utilisation d'Objective-C

Vous devez vous inscrire un UIApplicationWillEnterForegroundNotificationdans votre ViewControllerde viewDidLoadméthode et chaque fois que l' application revient de fond que vous pouvez faire ce que vous voulez faire dans la méthode enregistrées pour la notification. ViewController« s viewWillAppear ou viewDidAppear ne seront pas appelées lorsque l' application revient de fond au premier plan.

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

N'oubliez pas de désenregistrer la notification pour laquelle vous êtes inscrit.

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

Notez que si vous enregistrez votre viewControllerpour, UIApplicationDidBecomeActiveNotificationvotre méthode sera appelée chaque fois que votre application devient active, il n'est pas recommandé de vous inscrire viewControllerà cette notification.

Utilisation de Swift

Pour ajouter un observateur, vous pouvez utiliser le code suivant

 override func viewDidLoad() {
    super.viewDidLoad()

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

 func doYourStuff(){
     // your code
 }

Pour supprimer l'observateur, vous pouvez utiliser la fonction deinit de swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}
nsgulliver
la source
4
Oui c'est :) parfois il est difficile de trouver des réponses :)
nsgulliver
@nsgulliver Dois-je appeler manuellement unregister la notification - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. L'application le fera-t-elle pour moi?
ios le
43

Version Swift 3.0 ++

Dans votre viewDidLoad, inscrivez-vous au centre de notification pour écouter cette action ouverte en arrière-plan

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

Ajoutez ensuite cette fonction et effectuez l'action nécessaire

func doSomething(){
    //...
}

Enfin, ajoutez cette fonction pour nettoyer l'observateur de notification lorsque votre contrôleur de vue est détruit.

deinit {
    NotificationCenter.default.removeObserver(self)
}
Fangming
la source
Solution simple et directe pour gérer la notification à l'intérieur du VC +1
Mo Zaatar
Je ne peux pas croire que cette belle réponse soit manquée dans tant d'autres questions SO similaires / dupliquées.
Hugo Allexis Cardona
12

Swift 4.2. version

Inscrivez-vous au NotificationCenter viewDidLoadpour être averti lorsque l'application revient de l'arrière-plan

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

Implémentez la méthode qui doit être appelée.

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

Vous pouvez supprimer l'observateur une fois le ViewControllerfichier détruit. Ceci n'est requis que sous iOS9 et macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}
Gebirgsbärbel
la source
1
Pour votre information, je suis presque sûr que vous n'avez plus besoin de vous soucier de supprimer les observateurs ces jours-ci ...
Fattie
3

Demandez simplement à votre contrôleur de vue de s'inscrire à la UIApplicationWillEnterForegroundNotificationnotification et de réagir en conséquence.

andreagiavatto
la source
Comment vais-je faire ça? j'ai appelé mon viewController dans applicationDidBecomeActive mais. il chevauche viewController ou son amende pour le faire?
Zohaib
2
N'appelez pas votre viewController dans applicationDidBecomeActive (ce qui est faux de toute façon car il est appelé plusieurs fois). Inscrivez-vous à la notification dans votre viewDidLoadcomme @nsgulliver suggéré. Vous viewDidAppearappellerez également doYourStuffpour définir votre étiquette avec la valeur souhaitée.
andreagiavatto
3

Je pense que l'inscription à UIApplicationWillEnterForegroundNotification est risquée car vous pouvez vous retrouver avec plus d'un contrôleur réagissant à cette notification. Rien ne garantit que ces contrôleurs sont toujours visibles lorsque la notification est reçue.

Voici ce que je fais: Je force l'appel viewDidAppear sur le contrôleur actif directement à partir de la méthode didBecomeActive du délégué de l'application:

Ajoutez le code ci-dessous à - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];
Erwan
la source
7
Il est garanti si le contrôleur annule (comme il se doit) pour l'UIApplicationWillEnterForegroundNotification dans viewWillDisappear au lieu de dans dealloc. Appeler viewDidAppear ressemble explicitement à un hack pour moi, cela brise la sémantique (vue personnelle) et peut dérouter les gens (par expérience).
joakim
3

essayez d'ajouter cela dans AppDelegate applicationWillEnterForeground.

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

Selon la documentation d'Apple:

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

Description:
indique à un contrôleur enfant que son apparence est sur le point de changer. Si vous implémentez un contrôleur de conteneur personnalisé, utilisez cette méthode pour indiquer à l'enfant que ses vues sont sur le point d' apparaître ou de disparaître . Ne pas invoquer viewWillAppear:, viewWillDisappear:, viewDidAppear:ou viewDidDisappear:directement .

(void)endAppearanceTransition;

La description:

Indique à un contrôleur enfant que son apparence a changé. Si vous implémentez un contrôleur de conteneur personnalisé, utilisez cette méthode pour indiquer à l'enfant que la transition de vue est terminée.

Exemple de code:

(void)applicationDidEnterBackground:(UIApplication *)application
{

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

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

}

Question: Comment j'ai réparé?

Ans : J'ai trouvé ce morceau de lignes en application. Ces lignes ont fait que mon application ne recevait aucune notification ViewWillAppear. Quand j'ai commenté ces lignes, cela fonctionne très bien .

Lakshmi
la source