Який найкращий спосіб виявити, коли програма переходить у фоновий режим для мого перегляду?


78

У мене є контролер перегляду, який використовує NSTimerдля виконання якогось коду.

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

Відповіді:


172

Ви можете зацікавити будь-який клас, коли програма переходить у фоновий режим, отримувати сповіщення. Це хороша альтернатива поєднанню цих класів з AppDelegate.

При ініціалізації зазначених класів:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];

Відповідаючи на повідомлення

-(void)appWillResignActive:(NSNotification*)note
{

}
-(void)appWillTerminate:(NSNotification*)note
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];

}

2
Мені довелося зробити невелике виправлення для роботи цього коду: додавши двокрапку до імен методів всередині @selector, тобто замінивши @selector(appWillResignActive)на @selector(appWillResignActive:)(і те саме для @selector(appWillTerminate:)).
Піовезан

@Piovezan, причина, через яку вам потрібно ":", полягає в тому, що як би ви не називали свій метод, він все одно повинен приймати "..один і лише один аргумент (екземпляр NSNotification)." - Просто Alt + клацніть лівою кнопкою миші на декларації addObserver, щоб дізнатись більше.
serge-k

Чудова відповідь! Дякуємо, що врятували мене за волосся!
Septronic

willResignActive не означає, що він йде на другий план - це означає, що він стає неактивним. Наприклад, вхідний дзвінок у верхній частині програми зробить вас неактивними, як і спливаюче діалогове вікно системного рівня. UIApplicationDidEnterBackground - це сповіщення про фактичний перехід у фоновий режим.
chadbag

25

У Swift 4.0

override func viewDidLoad() {
    super.viewDidLoad()

    let app = UIApplication.shared

    //Register for the applicationWillResignActive anywhere in your app.
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.applicationWillResignActive(notification:)), name: NSNotification.Name.UIApplicationWillResignActive, object: app)
}

@objc func applicationWillResignActive(notification: NSNotification) {

}

1
Де ви скасовуєте реєстрацію сповіщення тут?
thexande

1
@thexande, якщо я правильно, Swift 4 робить це за вас, і вам більше не доведеться скасовувати реєстрацію сповіщення (якщо ви не можете зачекати ;-)
Стефан Пакет,

2
@StephanePaquet з документації Apple: "Якщо ваш додаток націлений на iOS 9.0 і новіші версії, або macOS 10.11 і новіші, вам не потрібно скасовувати реєстрацію спостерігача в його методі dealloc." :)
Rob VS

10

У ваших додатках AppDelegate (void)applicationDidEnterBackground:(UIApplication *)applicationметод буде викликаний iOS. Ви можете зупинити свій таймер там.


2
Ваш додаток також може зареєструватися для сповіщень UIApplicationDidEnterBackgroundNotification.
Марко

8

Для тих, хто хоче зробити це в Swift:

На init:

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplicationWillResignActiveNotification, object: nil)

На deinit:

NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationWillResignActiveNotification, object: nil)

Відповідаючи на повідомлення:

dynamic private func applicationWillResignActive() {
    // Do things here
}

Apple заохочує нас уникати динамічної диспетчеризації та селекторів Objective-C, коли це можливо в Swift, але це все ще найзручніший спосіб зробити це.


2

У швидкій версії 4.1:

Я використовую версію закриття:

var observer: NSObjectProtocol!

// inside init or viewDidLoad:
observer = NotificationCenter.default.addObserver(forName: .UIApplicationWillResignActive, object: nil, queue: nil) { _ in
    print("willResignActive")
}

deinit {
    NotificationCenter.default.removeObserver(observer)
}

addObserverМетод повертає непрозорий об'єкт , який повинен бути видалений в певний момент.


1

лише допоміжна примітка: Якщо ви реєструєте контролер A, щоб отримувати сповіщення про перехід у фоновий режим, будьте обережні, що він буде викликаний, навіть якщо ви (наприклад ..) натискаєте другий контролер B, і ви відображаєте B: Якщо ця поведінка неправильна , краще зареєструватися / скасувати реєстрацію в

didAppear / WillDisappear.


0

- (void)applicationWillResignActive:(UIApplication *)applicationна делегаті вашого додатка. Ви також можете зареєструватися для отримання UIApplicationWillResignActiveNotificationсповіщення про інші об'єкти.

Однак вам не обов'язково робити паузу таймера. Якщо ви нічого не зробите, програма все одно перейде в режим сну і не виконуватиме жодного коду. Імовірно, ваш таймер спрацює, коли ви знову станете активним (якщо ви це зробите). Якщо вам потрібно зробити щось особливе, існують методи делегування та сповіщення "дійсно стали активними", на які ви також можете зареєструватися.


Як уже згадувалося, існує "фонова" версія, яка дуже схожа на активну, якщо ви націлюєтесь лише на 4.0 та пізніші версії. "Активні" версії повертаються до версії 2.0.
smparkes

+1, не зрозумів, що у вас була частина сповіщення, коли я виклав свою відповідь
Джессі Блек

1
Строго кажучи, програма, яка виходить із активного стану, може не потрапити у фоновий стан (наприклад, у випадку тимчасового переривання, наприклад телефонного дзвінка або SMS).
Марко

1
@marco: погодився. Я був трохи швидким і розкутим. Багато людей (не можуть бути впевнені в OP) насправді не розрізняють неактивних та фонових. Я думав, зважаючи на те, як було сформульовано питання, що неактивний - це більше те, що він шукав, але, можливо, я пішов туди далеко. FWIW, деякі модальні спливаючі вікна з ОС (наприклад, для вимог мережі та місцезнаходження) також спричинять відставку.
smparkes

0

Свіфт 4:

init() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(applicationWillResignActive),
                                           name: NSNotification.Name.UIApplicationWillResignActive,
                                           object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self,
                                              name: NSNotification.Name.UIApplicationWillResignActive,
                                              object: nil)
}

@objc private func applicationWillResignActive() {
    self.header.blur.effect = nil
}

0

Це краще рішення із застосуванням закриття

Заявити спостерігачеві

var backgroundObserver: NSObjectProtocol?

Ініціалізуйте спостерігача в viewDidLoad

backgroundObserver = NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { [weak self] notification in
  // Do what you want to do when app would go to background/ resign active  
}

Не забудьте видалити спостерігача з деінциту

deinit {
    if let observer = backgroundObserver {
        NotificationCenter.default.removeObserver(observer)
    } 
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.