Почему viewWillAppear не вызывается, когда приложение возвращается из фона?
Я пишу приложение, и мне нужно, чтобы изменить мнение, если пользователь смотрит на приложение во время разговора по телефону.
я реализовал следующий метод:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"viewWillAppear:");
_sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height);
}
но это не вызывается, когда приложение возвращается на передний план.
Я знаю, что могу реализовать:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
но я не хочу этого делать. Я бы предпочел поместить всю информацию о макете в метод viewWillAppear:, и пусть это обрабатывает все возможное вариант развития событий.
Я даже пытался вызвать viewWillAppear: из applicationWillEnterForeground:, но я не могу точно определить, какой контроллер текущего представления в этот момент.
кто-нибудь знает правильный способ справиться с этим? Я уверен, что упускаю очевидное решение.
5 ответов
метод viewWillAppear
следует принимать в контексте того, что происходит в вашем собственном приложении, а не в контексте вашего приложения, помещаемого на передний план, когда вы переключаетесь на него из другого приложения.
другими словами, если кто-то смотрит на другое приложение или принимает телефонный звонок, а затем переключается обратно в приложение, которое ранее было на backgrounded, ваш UIViewController, который уже был виден, когда вы покинули приложение "не заботится", так сказать-насколько он обеспокоен, он никогда не исчезал, и он все еще виден - и так viewWillAppear
не называется.
Я рекомендую не вызывать viewWillAppear
себя -- он имеет определенное значение, которое вы не должны ниспровергать! Рефакторинг, который вы можете сделать для достижения того же эффекта, может быть следующим:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self doMyLayoutStuff:self];
}
- (void)doMyLayoutStuff:(id)sender {
// stuff
}
потом же триггер doMyLayoutStuff
из соответствующего уведомления:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];
нет никакого способа из коробки сказать, который является "текущим" UIViewController путь. Но вы можете найти способы обойти это, например, есть методы делегата UINavigationController для выяснения, когда UIViewController представлен в нем. Вы можете использовать такую вещь для отслеживания последнего UIViewController, который был представлен.
обновление
если вы раскладываете UIs с соответствующими масками авторезки на различных битах, иногда вам даже не нужно иметь дело с "ручной" выкладкой вашего пользовательского интерфейса - он просто получает дело с...
Свифт
короткий ответ:
использовать NotificationCenter
наблюдатель, а не viewWillAppear
.
override func viewDidLoad() {
super.viewDidLoad()
// set observer for UIApplicationWillEnterForeground
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
}
// my selector that was defined above
@objc func willEnterForeground() {
// do stuff
}
ответ
чтобы узнать, когда приложение возвращается из фона, использовать NotificationCenter
наблюдатель, а не viewWillAppear
. Вот пример проекта, который показывает, какие события происходят при. (Это адаптация эта цель-с ответа.)
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: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: NSNotification.Name.UIApplicationWillEnterForeground, 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")
}
}
на первый запуск приложения, порядок вывода:
view did load
view will appear
did become active
view did appear
после нажатия кнопки "Домой", а затем вернуть приложение на передний план, порядок вывода:
will enter foreground
did become active
Итак, если вы изначально пытались использовать viewWillAppear
затем UIApplicationWillEnterForeground
вероятно, это то, что вы хотите.
Примечание
начиная с iOS 9 и более поздних версий, вам не нужно удалять наблюдателя. The документация гласит:
если ваше приложение предназначено для iOS 9.0 и позже или macOS 10.11 и позже, вы не нужно отменять регистрацию наблюдателя в его
dealloc
метод.
используйте Центр уведомлений в viewDidLoad:
метод вашего ViewController для вызова метода и оттуда сделать то, что вы должны были сделать в вашем viewWillAppear:
метод. Зову viewWillAppear:
непосредственно не является хорошим вариантом.
- (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:
, один из самых запутанных методов в iOS SDKs, на мой взгляд, никогда не вызывается в такой ситуации, т. е. переключение приложений. Этот метод вызывается только в соответствии с отношением между представлением контроллера вида и окно приложения, т. е. сообщение отправляется контроллеру вида только в том случае, если его вид отображается в окне приложения, а не на экране.
когда ваше приложение идет фон, очевидно, самые верхние виды окна приложения не видны пользователю. Однако в перспективе окна приложения они по-прежнему являются самыми верхними видами, и поэтому они не исчезли из окна. Скорее, эти представления исчезли, потому что окно приложения исчезло. Они не исчезли, потому что исчезли!--7-->С окне.
поэтому, когда пользователь переключается обратно в ваше приложение, они, очевидно, появляются на экране, потому что окно появляется снова. Но с точки зрения окна, они вовсе не исчезли. Поэтому контроллеры представления никогда не получают viewWillAppear:animated
сообщение.
просто пытаюсь сделать это как можно проще см. код ниже:
- (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");
}