Obsługa aplikacjiDidBecomeActive - „Jak kontroler widoku może zareagować na aktywację aplikacji?”

179

Mam UIApplicationDelegateprotokół w mojej głównej klasie AppDelegate.m, ze applicationDidBecomeActivezdefiniowaną metodą.

Chcę wywołać metodę, gdy aplikacja powróci z tła, ale metoda znajduje się w innym kontrolerze widoku. Jak mogę sprawdzić, który kontroler widoku jest aktualnie wyświetlany w applicationDidBecomeActivemetodzie, a następnie wywołać metodę w tym kontrolerze?

Calvin
źródło

Odpowiedzi:

304

Każda klasa w twojej aplikacji może stać się „obserwatorem” dla różnych powiadomień w aplikacji. Kiedy tworzysz (lub ładujesz) kontroler widoku, musisz zarejestrować go jako obserwatora UIApplicationDidBecomeActiveNotificationi określić, którą metodę chcesz wywołać, gdy powiadomienie zostanie wysłane do aplikacji.

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(someMethod:)
                                             name:UIApplicationDidBecomeActiveNotification object:nil];

Nie zapomnij posprzątać po sobie! Pamiętaj o usunięciu się z roli obserwatora, gdy zniknie twój widok:

[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UIApplicationDidBecomeActiveNotification
                                              object:nil];

Więcej informacji o Centrum powiadomień .

Reed Olsen
źródło
Doskonały. Nie myślałem o użyciu NSNotificationCenter. Dziękuję Ci!
Calvin
3
Tylko literówka w tym wierszu kodu (brak „name”): [[NSNotificationCenter defaultCenter] addObserver: selektor własny: @selector (someMethod :) nazwa: UIApplicationDidBecomeActiveNotification obiekt: nil];
Johnus,
3
Aby dodać odpowiedź Reeda, wywoływana metoda (w tym przykładzie jest to metoda) musi zaakceptować parametr NSNotification. Tak więc sygnaturą metody someMethod byłoby - (void) someMethod: (NSNotification *) notification {// Zrób coś tutaj}
Aaron
2
@Aaron Może, ale nie jest to wymagane. To świetny wgląd. Dzięki!
Reed Olsen
Fantastyczny! Cóż to za świetny sposób na unieważnienie / odtworzenie instancji NSTimer bezpośrednio w kontrolerach widoku / innych obiektach odpowiedzialnych za te NSTimery. Kocham to!
idStar
68

Odpowiednik Swift 3, 4:

dodawanie obserwatora

NotificationCenter.default.addObserver(self,
    selector: #selector(applicationDidBecomeActive),
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

usunięcie obserwatora

NotificationCenter.default.removeObserver(self,
    name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
    object: nil)

oddzwonić

@objc func applicationDidBecomeActive() {
    // handle event
}
igrek
źródło
2
jak to nazwać?
1
@ user8169082, dodajesz obserwatora, gdziekolwiek chcesz zacząć otrzymywać powiadomienia. Możesz go dodać viewDidLoadlub viewWillAppear:animatedna przykład. I możesz usunąć obserwatora, gdy nie potrzebujesz już powiadomień lub gdy instancja obserwatora zostanie zwolniona w metodzie deinit
igrek
2
swift 4.2 Używam: NotificationCenter.default.addObserver (self, selektor: #selector (applicationDidBecomeActive (powiadomienie :)), nazwa: UIApplication.didBecomeActiveNotification, obiekt: zero)
Brian
16

Odpowiednik Swift 2 :

let notificationCenter = NSNotificationCenter.defaultCenter()

// Add observer:
notificationCenter.addObserver(self,
  selector:Selector("applicationWillResignActiveNotification"),
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove observer:
notificationCenter.removeObserver(self,
  name:UIApplicationWillResignActiveNotification,
  object:nil)

// Remove all observer for all notifications:
notificationCenter.removeObserver(self)

// Callback:
func applicationWillResignActiveNotification() {
  // Handle application will resign notification event.
}
Zorayr
źródło
Najlepsze miejsce na zastosowanie metody removeObserverSwift deinit:.
Enrico Susatyo
Zasadniczo dostęp do self in deinit nie jest zalecany; w tym momencie „ja” znajduje się pomiędzy całkowitym przydzieleniem a zwolnieniem
Zorayr
1
Gdzie zatem usunąłbyś serwer?
Enrico Susatyo
2
@EnricoSusatyo możesz to zignorować, ponieważ jest to nieprawidłowe. Przesłanianie deinit jest w porządku: „Ponieważ instancja nie jest zwalniana aż do momentu wywołania deinitializatora, deinitializator może uzyskać dostęp do wszystkich właściwości instancji, do której jest wywoływany, i może modyfikować swoje zachowanie na podstawie tych właściwości (takich jak wyszukiwanie nazwy plik, który musi zostać zamknięty). ” Wywołanie deinit nie jest w porządku
Dan Rosenstark
7

Szybki 4.2

Dodaj obserwatora

NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: UIApplication.didBecomeActiveNotification, object: nil)

Usuń obserwatora

NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)

Obsługa zdarzenia

@objc func handleEvent() {
}
Abhishek Jain
źródło
5

W Swift 4 Apple informuje za pośrednictwem nowego kompilatora ostrzeżenie, że unikamy korzystania z #selectortego w tym scenariuszu. Następujący sposób jest o wiele bezpieczniejszy.

Najpierw utwórz leniwy war, którego można użyć w powiadomieniu:

lazy var didBecomeActive: (Notification) -> Void = { [weak self] _ in
    // Do stuff
} 

Jeśli wymagają rzeczywistej powiadomienie być włączone, po prostu wymienić _się notification.

Następnie skonfigurujemy powiadomienie, aby obserwować, czy aplikacja stanie się aktywna.

func setupObserver() {
    _ = NotificationCenter.default.addObserver(forName: .UIApplicationDidBecomeActive,
                                               object: nil,
                                               queue:.main,
                                               using: didBecomeActive)
}

Duża zmiana polega na tym, że zamiast wywoływać a #selector, nazywamy teraz var utworzony powyżej. Może to wyeliminować sytuacje, w których występują nieprawidłowe awarie selektora.

Wreszcie usuwamy obserwatora.

func removeObserver() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
}
CodeBender
źródło
1
#selectormoże wywołać metodę zadeklarowaną jako @objcatrybut w Swift 4.
AnBisw 16.04.18
1
jest niepoprawny w użyciu, removeObserver(selfponieważ ja nie został przypisany podczas dodawania obserwatora. Powinieneś let observer = NotificationCenter.default.addObserverwtedyremoveObserver(observer
Yan Kalbaska
Dzięki @CodeBender Nie znałem jeszcze tej funkcji i to (w końcu) usuwa @objc. Jednak gdy próbuję, pojawia się ostrzeżenie w konsoli (Xcode 11.3.1 (11C504), Swift 13.3): Nie można zakończyć BackgroundTask: nie ma zadania w tle z identyfikatorem. Nawet jeśli zapisam obserwatora w zmiennej jako NSObjectProtocol.
palme
Nieważne, dostaję też ostrzeżenie, jeśli @objcużyję wariantu.
palme
3

Szybki 5

fileprivate  func addObservers() {
      NotificationCenter.default.addObserver(self,
                                             selector: #selector(applicationDidBecomeActive),
                                             name: UIApplication.didBecomeActiveNotification,
                                             object: nil)
    }

fileprivate  func removeObservers() {
        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
    }

@objc fileprivate func applicationDidBecomeActive() {
// here do your work
    }
Gurjinder Singh
źródło
0

Sposób łączenia:

import Combine

var cancellables = Set<AnyCancellable>()
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
    .sink { notification in
            // do stuff
    }.store(in: &cancellables)
ollie
źródło