ViewDidAppear не викликається під час відкриття програми з фону


175

У мене є контролер перегляду, в якому моє значення дорівнює 0 (мітка), і коли я відкриваю цей контролер перегляду з іншого, ViewControllerя встановив viewDidAppearна етикетці значення 20. Він відмінно працює , але коли я закриваю додаток і чим я знову відкрити моє додаток , але значення не зміниться , тому що viewDidLoad, viewDidAppearі viewWillAppearнічого додзвонився. Як мені зателефонувати, коли я відкриваю додаток. Чи треба мені щось робити applicationDidBecomeActive?


Ви можете опублікувати місцеве сповіщення, коли програма активується, і додати свій контролер подання як значення спостерігача та оновлення.
Аділ Соомро

Відповіді:


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

1
Дане, ти скопіював UIApplicationWillEnterForegroundNotification для appDidEnterForeground :. Це не трохи вводить в оману? Зауважте "буде" і "зробив". Це було навмисно?
Любилюк

@Lubiluk - не навмисно. Я відредагую. Хороший улов.
дан

4
Це була дуже корисна відповідь. Я зробив версію Swift його тут .
Сурагч

Ідеальна демонстрація фонового режиму!
Marcelo dos Santos

Яка послідовність подій, якщо двічі торкнутись кнопки додому та закрити додаток?
Амджад Хусейні

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)
}

4
Так, так :) іноді важко знайти відповіді :)
nsgulliver

@nsgulliver Чи потрібно вручну викликати скасування реєстрації сповіщення - (недійсне) dealloc {[[[NSNotificationCenter defaultCenter] deleteObserver: self]; }. Чи зробить це додаток для мене?
ios

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)
}

Легке та прямолінійне рішення для обробки повідомлень всередині VC +1
Пн Заатар

Не можу повірити, що ця приємна відповідь пропущена у багатьох інших подібних / дублюючих питаннях SO.
Хьюго Алексис Кардона

11

Швидкий 4.2. версія

Зареєструйтесь у центрі повідомлень, 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)
}

1
FYI Я впевнений , що вам не потрібно турбуватися видалення спостерігачів більше в ці дні ...
Fattie

3

Просто попросіть вашого контролера перегляду зареєструватися для UIApplicationWillEnterForegroundNotificationсповіщення та прореагувати відповідно.


Як я це зроблю? я закликав мій поглядController у 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 замість того, щоб мати змогу. Виклик viewDidAppear явно виглядає як хак для мене, він порушує семантику (особистий погляд) і може заплутати людей (з досвіду).
joakim

3

спробуйте додати це в додаток AppDelegateWillEnterForeground.

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

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. Коли я коментував ці рядки, це працює чудово .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.