Enviar e receber mensagens através do NSNotificationCenter no Objective-C?

610

Estou tentando enviar e receber mensagens NSNotificationCenterno Objective-C. No entanto, não consegui encontrar nenhum exemplo de como fazer isso. Como você envia e recebe mensagens NSNotificationCenter?

hichris123
fonte
Realmente muito útil, obrigado. Uma coisa, o método addObserver não deve ter o ponto e vírgula à direita após o seletor especificado (pelo menos, causou uma exceção na minha versão deste). Tentei editar o código acima, mas a alteração não foi aceita devido a problemas de formatação no código original.
Braunius 5/10
3
Isso foi ótimo: cocoawithlove.com/2008/06/…
Aram Kocharyan
2
este q é muito básico e amplo, um pouco de googleing teria sido bom #
Daij-Djan
Isso é muito semelhante a uma pergunta relacionada aqui: stackoverflow.com/questions/7896646/…
David Douglas
55
Acho que é a pergunta de um absurdo como este está fechado um não construtiva quando os usuários de Stack Overflow têm tão claramente comentou a sua utilidade
Chet

Respostas:

1019
@implementation TestClass

- (void) dealloc
{
    // If you don't remove yourself as an observer, the Notification Center
    // will continue to try and send notification objects to the deallocated
    // object.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (id) init
{
    self = [super init];
    if (!self) return nil;

    // Add this instance of TestClass as an observer of the TestNotification.
    // We tell the notification center to inform us of "TestNotification"
    // notifications using the receiveTestNotification: selector. By
    // specifying object:nil, we tell the notification center that we are not
    // interested in who posted the notification. If you provided an actual
    // object rather than nil, the notification center will only notify you
    // when the notification was posted by that particular object.

    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(receiveTestNotification:) 
        name:@"TestNotification"
        object:nil];

    return self;
}

- (void) receiveTestNotification:(NSNotification *) notification
{
    // [notification name] should always be @"TestNotification"
    // unless you use this method for observation of other notifications
    // as well.

    if ([[notification name] isEqualToString:@"TestNotification"])
        NSLog (@"Successfully received the test notification!");
}

@end

... em outro lugar em outra classe ...

- (void) someMethod
{

    // All instances of TestClass will be notified
    [[NSNotificationCenter defaultCenter] 
        postNotificationName:@"TestNotification" 
        object:self];

}
dreamlax
fonte
2
Apenas imaginando onde [NSNotificationCenter defaultCenter] deve ser colocado. É melhor colocá-lo no seu AppDelegate?
fulvio
14
@Fulvio: Depende, se você estiver recebendo ou postando notificações que potencialmente afetam todas as partes do seu aplicativo, coloque-o no AppDelegate. Se você estiver recebendo / postando notificações que afetam apenas uma única classe, coloque-a nessa classe.
dreamlax
1
@dreamlax Truth, no entanto, vale a pena notar, porque essa pergunta é pesquisada principalmente por novos desenvolvedores iOS que mantêm o ouvinte de notificação ativo por mais tempo do que o necessário. Agora, com o arco, você geralmente não usa o dealloc e, como resultado, alguns podem pensar que não precisam liberar o ouvinte.
Vive
7
Também vale a pena mencionar que a [super dealloc]chamada no método de desalocação não é permitida pelo ARC; o resto é tudo de bom.
19414 tommys
1
O que acontece se a notificação disparar e não houver observadores? A notificação está perdida? Ou é "salvo" em algum lugar pronto para ser enviado para um novo observador (criado posteriormente)?
Superpuccio 27/02
226

Para expandir o exemplo do dreamlax ... Se você deseja enviar dados junto com a notificação

Ao publicar o código:

NSDictionary *userInfo = 
[NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: 
                       @"TestNotification" object:nil userInfo:userInfo];

Ao observar o código:

- (void) receiveTestNotification:(NSNotification *) notification {

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
Michael Peterson
fonte
TestNotification deve ser do tipo NSString. É uma variável de instância NSNotification?
RomanHouse
1
Posso acessar o observador selfno método receiveTestNotification?
por que
porque sim. receiveTestNotification é um método de instância e você tem acesso à própria instância via self dentro dela.
Michael Peterson
É isso aí. Eu estava procurando uma maneira de obter o UserInfo do método receptor.
Hasan
Parece que toda essa ideia de observador não cobre todos os casos. isso não funcionou quando o aplicativo. foi fechado e um formulário de notificação no centro de notificações foi tocado. O método observador não é chamado.
Hasan
49

Este me ajudou:

// Add an observer that will respond to loginComplete
[[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(showMainMenu:) 
                                                 name:@"loginComplete" object:nil];


// Post a notification to loginComplete
[[NSNotificationCenter defaultCenter] postNotificationName:@"loginComplete" object:nil];


// the function specified in the same class where we defined the addObserver
- (void)showMainMenu:(NSNotification *)note {
    NSLog(@"Received Notification - Someone seems to have logged in"); 
}

Fonte: http://www.smipple.net/snippet/Sounden/Simple%20NSNotificationCenter%20example

j7nn7k
fonte
Isso funcionou para mim! Obrigado
Rakshitha Muranga Rodrigo
48

Existe também a possibilidade de usar blocos:

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] 
     addObserverForName:@"notificationName" 
     object:nil
     queue:mainQueue
     usingBlock:^(NSNotification *notification)
     {
          NSLog(@"Notification received!");
          NSDictionary *userInfo = notification.userInfo;

          // ...
     }];

Documentação da Apple

Xavi Gil
fonte
1
Esta é uma boa atualização para minha resposta, que está bastante desatualizada agora. Com a introdução ou ARC e bloqueios, os centros de notificação são muito mais fáceis de lidar.
dreamlax
5
Eu também pensava assim, mas acontece que é bom demais para ser verdade. Nesse caso, é necessário reter o observador que addObserver retorna e, posteriormente, removê-lo, o que o torna tão complicado quanto criar um novo método, se não mais. Mais informações: toastmo.com/blog/2012/12/04/…
Andrew
42

se você estiver usando o NSNotificationCenter para atualizar sua exibição, não se esqueça de enviá-la a partir do thread principal chamando dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});
eiran
fonte
1
é a postagem de notificação que precisa ocorrer a partir do encadeamento principal ou apenas quando você realmente atualiza a exibição, ou seja, dentro do método que recebe a notificação que você envia para o encadeamento principal?
precisa saber é o seguinte
1
o segmento para o qual você envia a notificação é o segmento executando as funções e, assim, tentando alterar a interface do usuário. você também pode usar o despacho para o thread principal dentro das funções, exatamente como você disse: D. deve ter o mesmo resultado, perheps é ainda melhor: D
Eiran
1
@eiran, muito obrigado bro, funcionou somente depois que eu escrevi dentro dispatch_async
Arshad Shaik
2

SWIFT 5.1 da resposta selecionada para iniciantes

class TestClass {
    deinit {
        // If you don't remove yourself as an observer, the Notification Center
        // will continue to try and send notification objects to the deallocated
        // object.
        NotificationCenter.default.removeObserver(self)
    }

    init() {
        super.init()

        // Add this instance of TestClass as an observer of the TestNotification.
        // We tell the notification center to inform us of "TestNotification"
        // notifications using the receiveTestNotification: selector. By
        // specifying object:nil, we tell the notification center that we are not
        // interested in who posted the notification. If you provided an actual
        // object rather than nil, the notification center will only notify you
        // when the notification was posted by that particular object.

        NotificationCenter.default.addObserver(self, selector: #selector(receiveTest(_:)), name: NSNotification.Name("TestNotification"), object: nil)
    }

    @objc func receiveTest(_ notification: Notification?) {
        // [notification name] should always be @"TestNotification"
        // unless you use this method for observation of other notifications
        // as well.

        if notification?.name.isEqual(toString: "TestNotification") != nil {
            print("Successfully received the test notification!")
        }
    }
}

... em outro lugar em outra classe ...

 func someMethod(){
        // All instances of TestClass will be notified
        NotificationCenter.default.post(name: "TestNotification", object: self)
 }
Maneesh M
fonte