applicationWillTerminate, когда он вызывается, а когда нет

Привет, я прочитал несколько вопросов на SO о том, что applicationWillTerminate вызывается и не вызывается.

Я хотел обобщить то, что я понял, поскольку есть несколько постов, которые говорят по-разному.

  1. Для IOS (без многозадачности) он вызывается всегда, когда нажата кнопка home.

  2. Для IOS 4 и выше

    а. не вызывается при нажатии кнопки "домой" (поскольку приложение переходит в фоновый режим)

    б. он вызывается при закрытии приложения из многозадачной док-станции, и если у приложения внезапный флаг завершения в файле info.plist отключен, в противном случае он не вызывается. (Я установил "Приложение должно получать события App Died", и даже тогда при закрытии приложения из многозадачной док-станции функция завершения не вызывалась)

Исходя из этого у меня было несколько вопросов

Это хорошая практика, чтобы установить, что приложение должно получить флаг событий App Died? (Я установил "Приложение должно получать события App Died", и даже тогда при закрытии приложения из многозадачной док-станции функция завершения не вызывалась)

или же

Является ли регистрация для "UIApplicationWillTerminateNotification" лучше, чем настройка info.plist?

По сути, мне нужно выполнять какую-то работу только тогда, когда приложение завершается, а НЕ когда оно переходит в фоновый режим.

или же

РЕДАКТИРОВАТЬ (1): Когда приложение завершается, в приложение отправляется следующее. Как мне это поймать?

Программа получила сигнал: "SIGKILL".

РЕДАКТИРОВАТЬ (2):

Обратите внимание: это не вызывается в IOS 4 и выше при удалении из дока многозадачности. Вы можете подумать, что это так. Но в моем случае это не так.

Я спрашиваю, знает ли кто-нибудь почему? Есть ли что-то еще, что я пропускаю.

Также обратите внимание, что я установил "Приложение должно получать события App Died", и даже тогда оно не вызывается.

РЕДАКТИРОВАТЬ (3):

Ответ на следующий вопрос также не сработал. applicationWillTerminate не вызывается

Кто-нибудь сталкивался с такой же проблемой, как я?

6 ответов

Короче, если у вас нет UIApplicationExitsOnSuspend в вашем Info.plist, установленном на YES, в iOS4 и выше нет гарантии, что applicationWillTerminate: когда-нибудь позвонят.

Как сказано в документации:

Для приложений, которые поддерживают фоновое выполнение, этот метод обычно не вызывается, когда пользователь выходит из приложения, потому что в этом случае приложение просто переходит в фоновый режим. Тем не менее, этот метод может быть вызван в ситуациях, когда приложение работает в фоновом режиме (не приостановлено), и система должна прекратить его по некоторым причинам.

(Акцент мой.)

Если вам нужно что-то сделать до выхода из приложения, вам нужно сделать это в applicationDidEnterBackground:, Нет возможности поймать SIGKILL.

Я вижу -applicationWillTerminate: вызывается с помощью следующего теста. В новом проекте (я использовал шаблон "Single View Application"), добавьте в AppDelegate следующее:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    __block UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        if (identifier != UIBackgroundTaskInvalid) {
            [[UIApplication sharedApplication] endBackgroundTask:identifier];
            identifier = UIBackgroundTaskInvalid;
        }
    }];

    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i=0; i < 20; i++) {
            NSLog(@"%d", i);
            sleep(1);
        }
        if (identifier != UIBackgroundTaskInvalid) {
            [[UIApplication sharedApplication] endBackgroundTask:identifier];
            identifier = UIBackgroundTaskInvalid;
        }
    });
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

В этом примере запускается фоновая задача, когда приложение переходит в фоновый режим. Задача задерживается всего на 20 секунд (с регистрацией раз в секунду), что позволяет приложению работать в фоновом режиме (обратите внимание на разницу между работой в фоновом режиме и приостановкой) на достаточно долгое время, чтобы его можно было удалить из переключателя приложений.

Таким образом, чтобы проверить его, запустите приложение, нажмите кнопку "Домой", чтобы отправить приложение в фоновый режим, затем, прежде чем задержка в 20 секунд истечет, удалите приложение из переключателя приложений. После конца 20-х годов -applicationWillTerminate: называется. Вы можете посмотреть консоль в Xcode, чтобы убедиться, что это так.

Я попробовал это в iOS Simulator для iOS 5.1 и 6.1 (оба iPhone) и увидел, что это происходит в обоих случаях. Я также тестировал на iPhone 4S под управлением iOS 6.1.2 и видел такое же поведение.

Как я знаю, есть 3 ситуации, когда ваше приложение умрет.

  1. Завершено конечным пользователем, вы можете сделать что-то в -[UIApplication applicationWillEnterBackground:], в таком случае, -[UIApplication applicationWillTerminate:] НЕ будет называться.

  2. Сброс системы, например, памяти недостаточно, вы можете сделать что-то в -[UIApplication applicationWillTerminate:]в этом случае мы НЕ знаем, applicationWillEnterBackground: был вызван;

  3. Сбой, ничего не может быть сделано, кроме как с помощью какого-либо инструмента отчетности о сбоях. (Отредактировано: ловить SIGKILL невозможно)

Источник: http://www.cocos2d-iphone.org/forum/topic/7386

Я скопировал код сохранения состояния из applicationWillTerminate в applicationDidEnterBackground, а также добавил логическое значение multitaskingEnabled, чтобы вызывать сохранение состояния только в applicationDidEnterBackground. ПОТОМУ ЧТО есть один экземпляр на многозадачном устройстве, где вызывается applicationWillTerminate: если приложение находится на переднем плане, и вы выключаете устройство. В этом случае и applicationDidEnterBackground, и applicationWillTerminate вызываются.

Поскольку мы знаем, что приложение имеет только 5 секунд, когда -applicationWillTerminate будучи призванным Так что если кто-то хочет обновить сервер в этот момент. Чем использовать синхронный вызов.

[NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&error];

Заметка:- -applicationWillTerminate не будет звонить, если приложение будет убито из приостановленного состояния. Приостановленное состояние означает, что приложение не работает в backgroupd. Одним из решений для этого является использование фоновой задачи.

На основании теста Эндрю я понимаю, что документы для applicationWillTerminate(_:) должны иметь следующие пояснения:

Для приложений, которые не поддерживают фоновое выполнение или связаны с iOS 3.x или более ранней версией, этот метод всегда вызывается, когда пользователь выходит из приложения. Для приложений, поддерживающих фоновое выполнение, этот метод обычно не вызывается [сразу], когда пользователь выходит из приложения, потому что в этом случае приложение просто переходит в фоновый режим. Однако этот метод может быть вызван [вместо beginBackgroundTask(expirationHandler:)] в ситуациях, когда приложение работает в фоновом режиме (не приостановлено) и системе по какой-то причине необходимо завершить его.

// абсолютный ответ applicationWillTerminate

func applicationWillTerminate (application: UIApplication) {

    print("applicatoinWillTerminate")

    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

Шаг 1: команда + Shift + H (двойной щелчок (вкладка))

шаг 2: переместить верхнюю часть приложения (убить)

шаг 3: applicationWillTerminate Work

Другие вопросы по тегам