ViewDidAppear не вызывается при открытии приложения из фона

175

У меня есть View Controller, в котором мое значение равно 0 (метка), и когда я открываю этот View Controller из другого, ViewControllerя установил viewDidAppearзначение 20 для метки. Он отлично работает , но когда я закрываю приложение и чем я снова открыть мое приложение , но значение не изменится , потому что viewDidLoad, viewDidAppearи viewWillAppearничего дозвонился. Как я могу позвонить, когда я открою свое приложение. Должен ли я сделать что-нибудь из applicationDidBecomeActive?

Zohaib
источник
Когда приложение станет активным, вы можете опубликовать локальное уведомление и добавить свой контроллер представления в качестве наблюдателя и обновить значения.
Адиль Соомро

Ответы:

314

Заинтересовавшись точной последовательностью событий, я оснастил приложение следующим образом: (@Zohaib, вы можете использовать приведенный ниже код NSNotificationCenter, чтобы ответить на ваш вопрос).

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

При запуске вывод выглядит так:

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

Введите фон, затем снова введите передний план:

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
Danh
источник
1
Дэн, вы отобразили UIApplicationWillEnterForegroundNotification на appDidEnterForeground :. Разве это не вводит в заблуждение? Обратите внимание на «будет» и «сделал». Это было намеренно?
Любилук
@Lubiluk - не намеренно. Я отредактирую Хороший улов.
Дан
4
Это был очень полезный ответ. Я сделал версию Swift здесь .
Сурагч
Отличная демонстрация фонового режима!
Марсело душ Сантуш
Какова последовательность событий, когда вы дважды нажимаете на кнопку «Домой» и закрываете приложение?
Амжад Хуссейни
134

Использование Objective-C

Вы должны зарегистрировать UIApplicationWillEnterForegroundNotificationв вашем ViewController«s viewDidLoadметод и всякий раз , когда приложение возвращается из фона , вы можете делать все , что вы хотите сделать в методе зарегистрированного уведомления. ViewController«S viewWillAppear или viewDidAppear не будет вызываться , когда приложение возвращается из фона на передний план.

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

Не забудьте отменить регистрацию уведомления, на которое вы зарегистрированы.

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

Примечание При регистрации viewControllerдля UIApplicationDidBecomeActiveNotificationто ваш метод будет вызываться каждый раз , когда ваше приложение становится активным, не рекомендуется регистрироваться viewControllerдля этого уведомления.

Использование Swift

Для добавления наблюдателя вы можете использовать следующий код

 override func viewDidLoad() {
    super.viewDidLoad()

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

 func doYourStuff(){
     // your code
 }

Для удаления наблюдателя вы можете использовать функцию deinit swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}
nsgulliver
источник
4
Да, это так :) Иногда трудно найти ответы :)
nsgulliver
@nsgulliver Нужно ли вручную вызывать отмену регистрации уведомления - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; } Будет ли приложение сделать это для меня?
ИОС
43

Версия Swift 3.0 ++

В вашем viewDidLoad, зарегистрироваться в центре уведомлений, чтобы прослушать это открытое из фонового действия

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

Затем добавьте эту функцию и выполните необходимые действия

func doSomething(){
    //...
}

Наконец добавьте эту функцию, чтобы очистить наблюдателя уведомлений, когда ваш контроллер представления разрушен.

deinit {
    NotificationCenter.default.removeObserver(self)
}
Fangming
источник
Простое и понятное решение для обработки уведомлений внутри ВК +1
Мо Заатар
Не могу поверить, что этот хороший ответ пропущен во многих других похожих / дублирующих SO вопросах.
Уго Аллексис Кардона
11

Свифт 4.2. версия

Зарегистрируйтесь в NotificationCenter, viewDidLoadчтобы получать уведомления, когда приложение возвращается из фона

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

Реализуйте метод, который должен быть вызван.

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

Вы можете удалить наблюдателя после ViewControllerуничтожения. Это требуется только ниже iOS9 и MacOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}
gebirgsbärbel
источник
1
К вашему сведению, я почти уверен, что вам больше не нужно убирать наблюдателей в эти дни ...
Толстяк
3

Просто зарегистрируйте контроллер вида для UIApplicationWillEnterForegroundNotificationуведомления и отреагируйте соответствующим образом.

andreagiavatto
источник
Как я это сделаю? я вызвал мой viewController в applicationDidBecomeActive, но. это перекрывает viewController или это нормально делать?
Зохайб
2
Не вызывайте ваш viewController в applicationDidBecomeActive (что в любом случае неверно, потому что он вызывается несколько раз). Зарегистрируйтесь для получения уведомления в вашем предложенном viewDidLoadкак @nsgulliver. Вы viewDidAppearтакже позвоните, doYourStuffчтобы установить метку с желаемым значением.
andreagiavatto
3

Я думаю, что регистрация для UIApplicationWillEnterForegroundNotification является рискованной, так как вы можете получить более одного контроллера, реагирующего на это уведомление. Ничто не гарантирует, что эти контроллеры все еще видны при получении уведомления.

Вот что я делаю: я принудительно вызываю viewDidAppear на активном контроллере прямо из делегата приложения методом didBecomeActive:

Добавьте код ниже, чтобы - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];
Эрвана
источник
7
Это гарантируется, если контроллер отменяет регистрацию (как и должно быть) для UIApplicationWillEnterForegroundNotification в viewWillDisappear, а не в dealloc. Вызов viewDidAppear явно выглядит для меня как хак, он нарушает семантику (личное представление) и может сбить людей с толку (из опыта).
Иоаким
3

попробуйте добавить это в AppDelegate applicationWillEnterForeground.

func applicationWillEnterForeground(_ application: UIApplication) {        
    // makes viewWillAppear run
    self.window?.rootViewController?.beginAppearanceTransition(true, animated: false)
    self.window?.rootViewController?.endAppearanceTransition()
}
richc
источник
2

Согласно документации Apple:

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

Описание:
Сообщает дочернему контроллеру, что его внешний вид скоро изменится. Если вы реализуете пользовательский контроллер контейнера, используйте этот метод, чтобы сообщить дочернему элементу о том, что его представления должны появиться или исчезнуть . Не вызывать viewWillAppear:, viewWillDisappear:, viewDidAppear:или viewDidDisappear:непосредственно .

(void)endAppearanceTransition;

Описание:

Сообщает дочернему контроллеру, что его внешний вид изменился. Если вы реализуете пользовательский контроллер контейнера, используйте этот метод, чтобы сообщить дочернему элементу, что переход представления завершен.

Образец кода:

(void)applicationDidEnterBackground:(UIApplication *)application
{

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

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

}

Вопрос: как я исправил?

Ответ : Я нашел этот кусок строк в приложении. Эти строки заставили мое приложение не получать никаких уведомлений ViewWillAppear. Когда я прокомментировал эти строки, все работает нормально .

Лакшми
источник