ViewDidAppear no se llama al abrir la aplicación desde el fondo


175

Tengo un controlador de vista en el que mi valor es 0 (etiqueta) y cuando abro ese controlador de vista desde otro ViewController, viewDidAppearconfiguré el valor 20 en la etiqueta. Funciona bien, pero cuando cierro mi aplicación y de nuevo abro la aplicación, pero el valor no cambia porque viewDidLoad, viewDidAppeary viewWillAppearnada se ha llamado. ¿Cómo puedo llamar cuando abro mi aplicación? ¿Tengo que hacer algo applicationDidBecomeActive?


Puede publicar una notificación local cuando la aplicación se active y agregar su controlador de vista como observador y actualizar los valores.
Adil Soomro

Respuestas:


314

Curioso por la secuencia exacta de eventos, instrumenté una aplicación de la siguiente manera: (@Zohaib, puede usar el código NSNotificationCenter a continuación para responder a su pregunta).

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

En el lanzamiento, la salida se ve así:

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

Ingrese el fondo y vuelva a ingresar al primer plano:

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, asignaste UIApplicationWillEnterForegroundNotification a appDidEnterForeground :. ¿No es eso un poco engañoso? Observe "will" y "did". ¿Fue eso intencional?
Lubiluk

@Lubiluk: no intencional. Lo editaré Buena atrapada.
danh

44
Esta fue una respuesta muy útil. Hice una versión de Swift aquí .
Suragch

¡Demostración perfecta del modo de fondo!
Marcelo dos Santos

¿Cuál es la secuencia de eventos cuando toca dos veces el botón de inicio y cierra la aplicación?
Amjad Husseini

134

Usando Objective-C

Usted debe registrar una UIApplicationWillEnterForegroundNotificationen su ViewController's viewDidLoadmétodo y cada vez que la aplicación se vuelve de fondo se puede hacer lo que quiere hacer en el método registrado para la notificación. ViewController'S viewWillAppear o viewDidAppear no serán llamados cuando la aplicación se vuelve de fondo al primer plano.

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

No olvide anular el registro de la notificación para la que está registrado.

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

Tenga en cuenta que si registra su viewControllerpara UIApplicationDidBecomeActiveNotificationentonces, se llamaría a su método cada vez que su aplicación se active, no se recomienda registrarse viewControllerpara esta notificación.

Usando Swift

Para agregar observador puede usar el siguiente código

 override func viewDidLoad() {
    super.viewDidLoad()

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

 func doYourStuff(){
     // your code
 }

Para eliminar el observador, puede usar la función deinit de swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}

44
Sí, es :) a veces es difícil encontrar respuestas :)
nsgulliver

@nsgulliver ¿Tengo que invocar manualmente cancelar el registro de la notificación - (nulo) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. ¿La aplicación lo hará por mí?
ios

43

Versión Swift 3.0 ++

En su viewDidLoad, regístrese en el centro de notificaciones para escuchar esto abierto desde la acción de fondo

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

Luego agregue esta función y realice la acción necesaria

func doSomething(){
    //...
}

Finalmente, agregue esta función para limpiar el observador de notificaciones cuando se destruya su controlador de vista.

deinit {
    NotificationCenter.default.removeObserver(self)
}

Solución fácil y directa para manejar la notificación dentro del VC +1
Mo Zaatar

No puedo creer que esta agradable respuesta se pierda en tantas otras preguntas SO similares / duplicadas.
Hugo Allexis Cardona

11

Swift 4.2. versión

Regístrese en NotificationCenter viewDidLoadpara recibir notificaciones cuando la aplicación regrese del fondo

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

Implemente el método que debería llamarse.

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

Puede eliminar el observador una vez que ViewControllerse destruye. Esto solo se requiere debajo de iOS9 y macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}

1
FYI, estoy bastante seguro de que ya no es necesario molestarse en retirar observadores en estos días ...
Fattie

3

Simplemente haga que su controlador de vista se registre para la UIApplicationWillEnterForegroundNotificationnotificación y reaccione en consecuencia.


¿Cómo voy a hacer eso? He llamado a mi viewController en applicationDidBecomeActive pero. se superpone viewController o está bien hacer eso?
Zohaib

2
No llame a su viewController en applicationDidBecomeActive (que de todos modos está mal porque se llama varias veces). Regístrese para viewDidLoadrecibir la notificación sugerida en @nsgulliver. Su viewDidAppeartambién llamar doYourStuffa configurar su etiqueta con el valor deseado.
andreagiavatto

3

Creo que registrarse para la UIApplicationWillEnterForegroundNotification es arriesgado, ya que puede terminar con más de un controlador reaccionando a esa notificación. Nada garantiza que estos controladores sigan siendo visibles cuando se reciba la notificación.

Esto es lo que hago: forzo la llamada viewDidAppear en el controlador activo directamente del método didBecomeActive del delegado de la aplicación:

Agregue el siguiente código a - (void)applicationDidBecomeActive:(UIApplication *)application

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

77
Se garantiza si el controlador cancela el registro (como debería) para UIApplicationWillEnterForegroundNotification en viewWillDisappear en lugar de en dealloc. Llamar viewDidAppear explícitamente me parece un truco, rompe la semántica (vista personal) y puede confundir a las personas (por experiencia).
joakim

3

intente agregar esto en AppDelegate applicationWillEnterForeground.

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

2

Según la documentación de Apple:

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

Descripción: le
dice a un controlador secundario que su apariencia está a punto de cambiar. Si está implementando un controlador de contenedor personalizado, use este método para decirle al niño que sus vistas están a punto de aparecer o desaparecer . No invoque viewWillAppear:, viewWillDisappear:, viewDidAppear:, o viewDidDisappear:directamente .

(void)endAppearanceTransition;

Descripción:

Le dice a un controlador secundario que su apariencia ha cambiado. Si está implementando un controlador de contenedor personalizado, use este método para decirle al niño que la transición de vista se ha completado.

Código de muestra:

(void)applicationDidEnterBackground:(UIApplication *)application
{

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

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

}

Pregunta: ¿Cómo lo solucioné?

Respuesta : Encontré este trozo de líneas en la aplicación. Estas líneas hicieron que mi aplicación no recibiera ninguna notificación de ViewWillAppear. Cuando comenté estas líneas está funcionando bien .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.