Manejo de applicationDidBecomeActive: "¿Cómo puede un controlador de vista responder a que la aplicación se active?"

179

Tengo el UIApplicationDelegateprotocolo en mi clase principal AppDelegate.m, con el applicationDidBecomeActivemétodo definido.

Quiero llamar a un método cuando la aplicación regrese del fondo, pero el método está en otro controlador de vista. ¿Cómo puedo verificar qué controlador de vista se muestra actualmente en el applicationDidBecomeActivemétodo y luego hacer una llamada a un método dentro de ese controlador?

Calvin
fuente

Respuestas:

304

Cualquier clase en su aplicación puede convertirse en un "observador" para diferentes notificaciones en la aplicación. Cuando cree (o cargue) su controlador de vista, querrá registrarlo como observador UIApplicationDidBecomeActiveNotificationy especificar qué método desea llamar cuando se envíe esa notificación a su aplicación.

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

¡No olvides limpiar después de ti mismo! Recuerde eliminarse como observador cuando su vista se vaya:

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

Más información sobre el Centro de notificaciones .

Reed Olsen
fuente
Excelente. No pensé en usar NSNotificationCenter. ¡Gracias!
Calvin
3
Solo un error tipográfico en esa línea de código (falta el 'nombre'): [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (someMethod :) name: UIApplicationDidBecomeActiveNotification object: nil];
Johnus
3
Para agregar a la respuesta de Reed, el método que se llama (en este ejemplo es someMethod) debe aceptar un parámetro NSNotification. Entonces, la firma del método para someMethod sería - (nulo) someMethod: (NSNotification *) notificación {// Do Something Here}
Aaron
2
@ Aaron Puede, pero no es un requisito. Sin embargo, esa es una gran idea. ¡Gracias!
Reed Olsen
¡Fantástico! Qué gran manera de invalidar / recrear las instancias de NSTimer que uno tiene, directamente en los controladores de vista / otros objetos que son responsables de esos NSTimers. ¡Quiéralo!
idStar
68

Swift 3, 4 Equivalente:

agregando observador

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

quitar observador

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

llamar de vuelta

@objc func applicationDidBecomeActive() {
    // handle event
}
igrek
fuente
2
donde llamo esto
1
@ user8169082, agrega un observador donde sea necesario para comenzar a recibir notificaciones. Puede agregarlo en viewDidLoado viewWillAppear:animatedpor ejemplo. Y puede eliminar un observador cuando ya no necesite notificaciones, o cuando su instancia de observador se desasigne en el método
deinit
2
swift 4.2 Estoy usando: NotificationCenter.default.addObserver (self, selector: #selector (applicationDidBecomeActive (notificación :)), nombre: UIApplication.didBecomeActiveNotification, objeto: nulo)
Brian
16

Equivalente a 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
fuente
El mejor lugar para poner removeObserveren Swift: deinitmétodo.
Enrico Susatyo
En general, no se recomienda acceder a sí mismo en deinit; en este punto, self está en medio de ser completamente asignado y ser desasignado
Zorayr
1
¿Dónde eliminarías Observer entonces?
Enrico Susatyo
2
@EnricoSusatyo puedes ignorar eso, ya que no es correcto. Anular la deinit está bien: "Debido a que una instancia no se desasigna hasta después de que se llama a su desinicializador, un desinicializador puede acceder a todas las propiedades de la instancia a la que se llama y puede modificar su comportamiento en función de esas propiedades (como buscar el nombre de un archivo que necesita ser cerrado) ". Llamar a deinit no está bien
Dan Rosenstark
7

Swift 4.2

Añadir observador

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

Eliminar observador

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

Manejar evento

@objc func handleEvent() {
}
Abhishek Jain
fuente
5

Con Swift 4, Apple informa a través de una nueva advertencia de compilación que evitamos el uso #selectoren este escenario. La siguiente es una forma mucho más segura de lograr esto:

Primero, cree una var perezosa que pueda usar la notificación:

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

Si necesita que se incluya la notificación real, simplemente reemplácela _con notification.

A continuación, configuramos la notificación para observar si la aplicación se activa.

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

El gran cambio aquí es que en lugar de llamar a #selector, ahora llamamos a la var creada anteriormente. Esto puede eliminar situaciones donde se producen bloqueos de selector no válidos.

Finalmente, eliminamos al observador.

func removeObserver() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
}
CodeBender
fuente
1
#selectorpuede llamar a un método declarado como @objcatributo en Swift 4.
AnBisw
1
es incorrecto de usar removeObserver(selfporque self no se asignó al agregar observador. let observer = NotificationCenter.default.addObserverEntonces deberíasremoveObserver(observer
Yan Kalbaska
Gracias @CodeBender Todavía no conocía esa función y (finalmente) elimina la @objc. Sin embargo, cuando lo intento, aparece una advertencia en la consola (Xcode 11.3.1 (11C504), Swift 13.3): No se puede finalizar BackgroundTask: no existe una tarea en segundo plano con el identificador. Incluso si guardo el observador en una variable como NSObjectProtocol.
palma
No importa, también recibo la advertencia si uso la @objcvariante.
palma
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
fuente
0

La forma combinada:

import Combine

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