Manipulando applicationDidBecomeActive - “Como um controlador de exibição pode responder ao aplicativo se tornar ativo?”

179

Eu tenho o UIApplicationDelegateprotocolo na minha classe principal AppDelegate.m, com o applicationDidBecomeActivemétodo definido.

Quero chamar um método quando o aplicativo retornar do plano de fundo, mas o método está em outro controlador de exibição. Como posso verificar qual controlador de exibição está sendo exibido no applicationDidBecomeActivemétodo e fazer uma chamada para um método dentro desse controlador?

Calvin
fonte

Respostas:

304

Qualquer classe no seu aplicativo pode se tornar um "observador" para diferentes notificações no aplicativo. Ao criar (ou carregar) seu controlador de exibição, você deve registrá-lo como um observador UIApplicationDidBecomeActiveNotificatione especificar o método que deseja chamar quando essa notificação for enviada ao seu aplicativo.

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

Não se esqueça de limpar depois de si mesmo! Lembre-se de se remover como observador quando sua visão estiver desaparecendo:

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

Mais informações sobre o Centro de Notificação .

Reed Olsen
fonte
Excelente. Não pensou em usar NSNotificationCenter. Obrigado!
Calvin
3
Apenas um erro de digitação nessa linha de código (ausente 'nome'): [[NSNotificationCenter defaultCenter] addObserver: auto-seletor: @selector (someMethod :) nome: objeto UIApplicationDidBecomeActiveNotification: nil];
Johnus 12/11/10
3
Para adicionar à resposta de Reed, o método chamado (neste exemplo, é algumMétodo) precisa aceitar um parâmetro NSNotification. Portanto, a assinatura do método para someMethod seria - (void) someMethod: (NSNotification *) notificação {// Do Something aqui}
Aaron
2
@ Aaron Pode, mas não é um requisito. Essa é uma ótima visão, no entanto. Obrigado!
Reed Olsen
Fantástico! Que maneira excelente de invalidar / recriar as instâncias do NSTimer, mesmo na exibição de controladores / outros objetos responsáveis ​​por esses NSTimers. Adoro!
IdStar
68

Swift 3, 4 Equivalente:

adicionando observador

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

removendo observador

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

ligue de volta

@objc func applicationDidBecomeActive() {
    // handle event
}
igrek
fonte
2
onde eu chamo isso?
1
@ user8169082, você adiciona um observador sempre que precisar começar a receber notificações. Você pode adicioná-lo viewDidLoadou viewWillAppear:animatedpor exemplo. E você pode remover um observador quando há notificações necessidade mais longos, ou quando sua instância observador vai ser desalocado no método deinit
igrek
2
swift 4.2 Estou usando: NotificationCenter.default.addObserver (self, seletor: #selector (applicationDidBecomeActive (notificação :)), nome: UIApplication.didBecomeActiveNotification, objeto: nil)
Brian
16

Swift 2 Equivalente :

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
fonte
Melhor lugar para colocar removeObserverno Swift: deinitmétodo.
Enrico Susatyo
Geralmente, acessar o self in deinit não é recomendado; Neste ponto, eu é entre ser totalmente alocado e sendo desalocada
Zorayr
1
Onde você removeriaObserver então?
Enrico Susatyo
2
@EnricoSusatyo você pode ignorar isso, pois não está correto. Substituir desinit é bom: "Como uma instância não é desalocada até depois que seu desinicializador é chamado, um desinitializador pode acessar todas as propriedades da instância em que é chamado e pode modificar seu comportamento com base nessas propriedades (como procurar o nome de um arquivo que precisa ser fechado). " Chamando deinit não é ok
Dan Rosenstark
7

Swift 4.2

Adicionar observador-

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

Remova o observador

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

Lidar com evento

@objc func handleEvent() {
}
Abhishek Jain
fonte
5

Com o Swift 4, a Apple aconselha, por meio de um novo aviso do compilador, que evitamos o uso #selectornesse cenário. A seguir, é uma maneira muito mais segura de fazer isso:

Primeiro, crie uma var lenta que possa ser usada pela notificação:

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

Se você precisar que a notificação real seja incluída, substitua _por notification.

Em seguida, configuramos a notificação para observar a ativação do aplicativo.

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

A grande mudança aqui é que, em vez de chamar a #selector, agora chamamos o var criado acima. Isso pode eliminar situações nas quais você obtém falhas inválidas no seletor.

Finalmente, removemos o observador.

func removeObserver() {
    NotificationCenter.default.removeObserver(self, name: .UIApplicationDidBecomeActive, object: nil)
}
CodeBender
fonte
1
#selectorpode chamar um método declarado como um @objcatributo na Swift 4.
AnBisw
1
é incorreto usar removeObserver(selfporque o self não foi atribuído ao adicionar observador. Você deveria let observer = NotificationCenter.default.addObserverentãoremoveObserver(observer
Yan Kalbaska
Obrigado @ CodeBender Eu ainda não conhecia essa função e (finalmente) remove a @objc. No entanto, ao tentar, recebo um aviso no console (Xcode 11.3.1 (11C504), Swift 13.3): Não é possível finalizar a BackgroundTask: não existe tarefa em segundo plano com o identificador. Mesmo se eu salvar o observador em uma variável como NSObjectProtocol.
palme 29/01
Deixa pra lá também recebo o aviso se usar a @objcvariante.
palme 29/01
3

Swift 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
fonte
0

A maneira da combinação:

import Combine

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