Gestion de applicationDidBecomeActive - «Comment un contrôleur de vue peut-il répondre à l'application devenant active?»

179

J'ai le UIApplicationDelegateprotocole dans ma classe principale AppDelegate.m, avec la applicationDidBecomeActiveméthode définie.

Je veux appeler une méthode lorsque l'application revient de l'arrière-plan, mais la méthode est dans un autre contrôleur de vue. Comment puis-je vérifier quel contrôleur de vue est actuellement affiché dans la applicationDidBecomeActiveméthode, puis appeler une méthode dans ce contrôleur?

Calvin
la source

Réponses:

304

Toute classe de votre application peut devenir un «observateur» pour différentes notifications dans l'application. Lorsque vous créez (ou chargez) votre contrôleur de vue, vous souhaiterez l'enregistrer en tant qu'observateur pour le UIApplicationDidBecomeActiveNotificationet spécifier la méthode que vous souhaitez appeler lorsque cette notification est envoyée à votre application.

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(someMethod:)
                                             name:UIApplicationDidBecomeActiveNotification object:nil];

N'oubliez pas de nettoyer après vous! N'oubliez pas de vous retirer en tant qu'observateur lorsque votre vue disparaît:

[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UIApplicationDidBecomeActiveNotification
                                              object:nil];

Plus d'informations sur le centre de notifications .

Reed Olsen
la source
Excellent. Je n'ai pas pensé à utiliser NSNotificationCenter. Je vous remercie!
Calvin le
3
Juste une faute de frappe dans cette ligne de code («nom» manquant): [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (someMethod :) nom: UIApplicationDidBecomeActiveNotification object: nil];
Johnus
3
Pour ajouter à la réponse de Reed, la méthode appelée (dans cet exemple, c'est someMethod) doit accepter un paramètre NSNotification. Ainsi, la signature de la méthode pour someMethod serait - (void) someMethod: (NSNotification *) notification {// Do Something Here}
Aaron
2
@Aaron C'est possible, mais ce n'est pas une obligation. C'est une bonne idée, cependant. Merci!
Reed Olsen
Fantastique! Quelle excellente façon d'invalider / recréer les instances de NSTimer, directement dans les contrôleurs de vue / autres objets qui sont responsables de ces NSTimers. Aimer!
idStar
68

Swift 3, 4 équivalent:

ajout d'observateur

NotificationCenter.default.addObserver(self,
    selector: #selector(applicationDidBecomeActive),
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

suppression d'observateur

NotificationCenter.default.removeObserver(self,
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

rappeler

@objc func applicationDidBecomeActive() {
    // handle event
}
igrek
la source
2
où est-ce que j'appelle ça?
1
@ user8169082, vous ajoutez un observateur partout où vous devez commencer à recevoir des notifications. Vous pouvez l'ajouter sur viewDidLoadou viewWillAppear:animatedpar exemple. Et vous pouvez supprimer un observateur lorsque vous n'avez plus besoin de notifications, ou lorsque votre instance d'observateur va être désallouée dans la méthode
deinit
2
swift 4.2 J'utilise: NotificationCenter.default.addObserver (self, selector: #selector (applicationDidBecomeActive (notification :)), nom: UIApplication.didBecomeActiveNotification, objet: nil)
Brian
16

Équivalent Swift 2 :

let notificationCenter = NSNotificationCenter.defaultCenter()

// Add observer:
notificationCenter.addObserver(self,
  selector:Selector("applicationWillResignActiveNotification"),
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove observer:
notificationCenter.removeObserver(self,
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove all observer for all notifications:
notificationCenter.removeObserver(self)

// Callback:
func applicationWillResignActiveNotification() {
  // Handle application will resign notification event.
}
Zorayr
la source
Meilleur endroit pour mettre removeObserverSwift: deinitméthode.
Enrico Susatyo
Généralement, accéder à soi-même n'est pas conseillé; à ce stade, le moi est entre être entièrement attribué et désalloué
Zorayr
1
Où supprimeriez-vous alors l'Observer?
Enrico Susatyo
2
@EnricoSusatyo vous pouvez ignorer cela, car ce n'est pas correct. Le remplacement de deinit est très bien: "Dans la mesure où une instance n'est pas désallouée tant que son désinitialiseur n'a pas été appelé, un désinitialiseur peut accéder à toutes les propriétés de l'instance sur laquelle il est appelé et peut modifier son comportement en fonction de ces propriétés (comme rechercher le nom d'un fichier qui doit être fermé). " Appeler deinit n'est pas ok
Dan Rosenstark
7

Swift 4.2

Ajouter un observateur

NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: UIApplication.didBecomeActiveNotification, object: nil)

Supprimer l'observateur

NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)

Gérer l'événement

@objc func handleEvent() {
}
Abhishek Jain
la source
5

Avec Swift 4, Apple conseille via un nouvel avertissement du compilateur que nous évitons d'utiliser #selectordans ce scénario. Voici un moyen beaucoup plus sûr d'accomplir cela:

Tout d'abord, créez une var paresseuse qui peut être utilisée par la notification:

lazy var didBecomeActive: (Notification) -> Void = { [weak self] _ in
    // Do stuff
} 

Si vous souhaitez que la notification réelle soit incluse, remplacez simplement le _par notification.

Ensuite, nous configurons la notification pour observer l'activation de l'application.

func setupObserver() {
    _ = NotificationCenter.default.addObserver(forName: .UIApplicationDidBecomeActive,
                                               object: nil,
                                               queue:.main,
                                               using: didBecomeActive)
}

Le grand changement ici est qu'au lieu d'appeler a #selector, nous appelons maintenant le var créé ci-dessus. Cela peut éliminer les situations dans lesquelles vous obtenez des plantages de sélecteurs non valides.

Enfin, nous supprimons l'observateur.

func removeObserver() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
}
CodeBender
la source
1
#selectorpeut appeler une méthode déclarée comme @objcattribut dans Swift 4.
AnBisw
1
il est incorrect à utiliser removeObserver(selfcar self n'a pas été attribué lors de l'ajout d'observateur. Vous devriez let observer = NotificationCenter.default.addObserveralorsremoveObserver(observer
Yan Kalbaska
Merci @CodeBender Je ne connaissais pas encore cette fonction et elle supprime (enfin) le fichier @objc. Cependant, lorsque je l'essaye, j'obtiens un avertissement dans la console (Xcode 11.3.1 (11C504), Swift 13.3): Impossible de terminer BackgroundTask: aucune tâche d'arrière-plan n'existe avec l'identifiant. Même si je sauvegarde l'observateur dans une variable sous NSObjectProtocol.
palme le
Nevermind je reçois également l'avertissement si j'utilise la @objcvariante.
palme le
3

Swift 5

fileprivate  func addObservers() {
      NotificationCenter.default.addObserver(self,
                                             selector: #selector(applicationDidBecomeActive),
                                             name: UIApplication.didBecomeActiveNotification,
                                             object: nil)
    }

fileprivate  func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    }

@objc fileprivate func applicationDidBecomeActive() {
// here do your work
    }
Gurjinder Singh
la source
0

La manière de combiner:

import Combine

var cancellables = Set<AnyCancellable>()
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
    .sink { notification in
            // do stuff
    }.store(in: &cancellables)
ollie
la source