ios objective-c iphone viewwillappear

ios - ¿Por qué no se llama a viewWillAppear cuando una aplicación vuelve del fondo?



objective-c iphone (5)

Rápido

Respuesta corta

Use un observador de NotificationCenter lugar de viewWillAppear .

override func viewDidLoad() { super.viewDidLoad() // set observer for UIApplication.willEnterForegroundNotification NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } // my selector that was defined above @objc func willEnterForeground() { // do stuff }

Respuesta larga

Para saber cuándo una aplicación regresa del fondo, use un observador de NotificationCenter lugar de viewWillAppear . Aquí hay un proyecto de muestra que muestra qué eventos suceden cuando. (Esta es una adaptación de esta respuesta de Objective-C ).

import UIKit class ViewController: UIViewController { // MARK: - Overrides override func viewDidLoad() { super.viewDidLoad() print("view did load") // add notification observers NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) } override func viewWillAppear(_ animated: Bool) { print("view will appear") } override func viewDidAppear(_ animated: Bool) { print("view did appear") } // MARK: - Notification oberserver methods @objc func didBecomeActive() { print("did become active") } @objc func willEnterForeground() { print("will enter foreground") } }

Al iniciar la aplicación por primera vez, el orden de salida es:

view did load view will appear did become active view did appear

Después de presionar el botón de inicio y luego volver a poner la aplicación en primer plano, el orden de salida es:

will enter foreground did become active

Entonces, si originalmente intentabas usar viewWillAppear entonces UIApplication.willEnterForegroundNotification es probablemente lo que quieres.

Nota

A partir de iOS 9 y versiones posteriores, no es necesario eliminar el observador. La documentation establece:

Si su aplicación se dirige a iOS 9.0 y versiones posteriores o macOS 10.11 y versiones posteriores, no necesita anular el registro de un observador en su método dealloc .

Estoy escribiendo una aplicación y necesito cambiar la vista si el usuario está mirando la aplicación mientras habla por teléfono.

He implementado el siguiente método:

- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"viewWillAppear:"); _sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height); }

Pero no se llama cuando la aplicación vuelve al primer plano.

Sé que puedo implementar:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

pero no quiero hacer esto Preferiría poner toda mi información de diseño en el método viewWillAppear: y permitir que maneje todos los escenarios posibles.

Incluso he intentado llamar a viewWillAppear: from applicationWillEnterForeground :, pero parece que no puedo identificar cuál es el controlador de vista actual en ese momento.

¿Alguien sabe la forma correcta de lidiar con esto? Estoy seguro de que me falta una solución obvia.


El método viewWillAppear debe tomarse en el contexto de lo que está sucediendo en su propia aplicación, y no en el contexto de su aplicación que se coloca en primer plano cuando se vuelve a cambiar desde otra aplicación.

En otras palabras, si alguien mira otra aplicación o recibe una llamada telefónica, luego regresa a la aplicación que tenía anteriormente en segundo plano, su UIViewController que ya estaba visible cuando dejó su aplicación "no importa", por así decirlo. en lo que a él respecta, nunca desaparece y sigue siendo visible, por lo que viewWillAppear no se llama.

Recomiendo no llamar a la vista. viewWillAppear : ¡tiene un significado específico que no debes subvertir! Una refactorización que puede hacer para lograr el mismo efecto podría ser la siguiente:

- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self doMyLayoutStuff:self]; } - (void)doMyLayoutStuff:(id)sender { // stuff }

Luego, también doMyLayoutStuff desde la notificación apropiada:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];

Por cierto, no hay una forma inmediata de saber cuál es el UIViewController ''actual''. Pero puede encontrar formas de solucionarlo, por ejemplo, hay métodos de delegado de UINavigationController para averiguar cuándo se presenta un UIViewController en el mismo. Podría usar tal cosa para rastrear el último UIViewController que se ha presentado.

Actualizar

Si diseña UIs con las máscaras de autorizing adecuadas en los distintos bits, a veces ni siquiera necesita lidiar con el ''manual'' que se encuentra fuera de su UI, simplemente se trata con ...


Solo tratando de hacerlo lo más fácil posible, vea el código a continuación:

- (void)viewDidLoad { [self appWillEnterForeground]; //register For Application Will enterForeground } - (id)appWillEnterForeground{ //Application will enter foreground. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(allFunctions) name:UIApplicationWillEnterForegroundNotification object:nil]; return self; } -(void) allFunctions{ //call any functions that need to be run when application will enter foreground NSLog(@"calling all functions...application just came back from foreground"); }


Use el Centro de notificaciones en el método viewDidLoad: de su ViewController para llamar a un método y desde allí haga lo que se supone que debe hacer en su método viewWillAppear: . Llamar a viewWillAppear: directamente no es una buena opción.

- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"view did load"); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationIsActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } - (void)applicationIsActive:(NSNotification *)notification { NSLog(@"Application Did Become Active"); } - (void)applicationEnteredForeground:(NSNotification *)notification { NSLog(@"Application Entered Foreground"); }


viewWillAppear:animated: en mi opinión, uno de los métodos más confusos en los SDK de iOS en mi opinión, nunca se invoca en una situación de este tipo, es decir, el cambio de aplicación. Ese método solo se invoca según la relación entre la vista del controlador de vista y la ventana de la aplicación , es decir, el mensaje se envía a un controlador de vista solo si su vista aparece en la ventana de la aplicación, no en la pantalla.

Cuando su aplicación se pone en segundo plano, obviamente las vistas superiores de la ventana de la aplicación ya no son visibles para el usuario. Sin embargo, en la perspectiva de la ventana de la aplicación, siguen siendo las vistas más altas y, por lo tanto, no desaparecieron de la ventana. Más bien, esas vistas desaparecieron porque la ventana de la aplicación desapareció. No desaparecieron porque desaparecieron de la ventana.

Por lo tanto, cuando el usuario cambia de nuevo a su aplicación, obviamente parecen aparecer en la pantalla, porque la ventana aparece nuevamente. Pero desde la perspectiva de la ventana, no han desaparecido en absoluto. Por lo tanto, los controladores de vista nunca obtienen el mensaje viewWillAppear:animated .