¿Enviar y recibir mensajes a través de NSNotificationCenter en Objective-C?

610

Estoy intentando enviar y recibir mensajes a través NSNotificationCenterde Objective-C. Sin embargo, no he podido encontrar ningún ejemplo sobre cómo hacer esto. ¿Cómo se envían y reciben mensajes NSNotificationCenter?

hichris123
fuente
Realmente muy útil, gracias. Una cosa, el método addObserver no debería tener el punto y coma final después del selector especificado (al menos causó una excepción en mi versión de esto). Intenté editar el código anterior, pero el cambio no fue aceptado debido a problemas de formato en el código original.
Braunius
3
Esto fue genial: cocoawithlove.com/2008/06/…
Aram Kocharyan
2
esto es demasiado básico y amplio, un pequeño googleing hubiera sido bueno
Daij-Djan
Esto es muy similar a una pregunta relacionada aquí: stackoverflow.com/questions/7896646/…
David Douglas
55
Me parece absurdo que una pregunta como esta se cierre y no sea constructiva cuando los usuarios de Stack Overflow han comentado tan claramente su utilidad
Chet

Respuestas:

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

... en otro lugar de otra clase ...

- (void) someMethod
{

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

}
dreamlax
fuente
2
Me pregunto dónde se debe colocar [NSNotificationCenter defaultCenter]. ¿Es mejor colocarlo en su AppDelegate?
fulvio
14
@Fulvio: Depende, si está recibiendo o publicando notificaciones que potencialmente afectan a todas las partes de su aplicación, póngala en su AppDelegate. Si está recibiendo / publicando notificaciones que solo afectan a una sola clase, colóquela en esa clase.
dreamlax
1
@dreamlax Verdad, sin embargo, vale la pena notarlo porque esta pregunta es buscada principalmente por nuevos desarrolladores de ios que mantienen vivo al oyente de notificaciones más tiempo del que necesitan. Ahora con el arco, por lo general, no usa dealloc y, como resultado, algunos pueden pensar que no tienen que liberar al oyente.
Vive el
77
También vale la pena mencionar que la [super dealloc]llamada en el método dealloc no está permitida por ARC; El resto está todo bien.
tommys
1
¿Qué sucede si la notificación se dispara y no hay observadores? ¿Se pierde la notificación? ¿O está "guardado" en algún lugar listo para ser enviado a un nuevo observador (creado después)?
superpuccio
226

Para ampliar el ejemplo de dreamlax ... Si desea enviar datos junto con la notificación

En el código de publicación:

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

En observar el código:

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

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
Michael Peterson
fuente
TestNotification debe ser del tipo NSString. ¿Es una instancia de NSNotification variable?
RomanHouse
1
¿Puedo acceder al observador selfen el método acceptTestNotification?
por qué
porque?, si. ReceiveTestNotification es un método de instancia, y usted tiene acceso a la instancia a través de uno mismo dentro de él.
Michael Peterson
Eso es. Estaba buscando una manera de obtener UserInfo del método del receptor.
hasan
Parece que toda esa idea de observador no cubre todos los casos. esto no funcionó cuando la aplicación. se cerró y un formulario de notificación del centro de notificaciones fue intervenido. no se llama al método del observador.
hasan
49

Este me ayudó:

// 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"); 
}

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

j7nn7k
fuente
Eso funcionó para mí! Gracias
Rakshitha Muranga Rodrigo
48

También existe la posibilidad de usar bloques:

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

          // ...
     }];

Documentación de Apple

Xavi Gil
fuente
1
Esta es una buena actualización de mi respuesta que está bastante desactualizada ahora. Con la introducción o ARC y bloques, los centros de notificación son mucho más fáciles de manejar.
dreamlax
55
Yo también lo pensé, pero resulta que es demasiado bueno para ser verdad. En este caso, debe conservar el observador que devuelve addObserver y luego eliminarlo, lo que lo hace tan complicado como crear un nuevo método, si no más. Más información: toastmo.com/blog/2012/12/04/…
Andrew
42

si está utilizando NSNotificationCenter para actualizar su vista, no olvide enviarlo desde el hilo principal llamando a dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});
eiran
fuente
1
¿es la publicación de notificación que debe ocurrir desde el hilo principal, o justo cuando realmente actualiza la vista, es decir, dentro del método que recibe la notificación que envía al hilo principal?
Crashalot
1
el hilo desde el que envía la notificación es el hilo que ejecuta las funciones y, por lo tanto, intenta cambiar la interfaz de usuario. También puede usar el envío al hilo principal dentro de las funciones, tal como dijo: D. debería tener el mismo resultado, perheps es aún mejor: D
eiran
1
@eiran, muchas gracias hermano, funcionó solo después de que escribí dentro de dispatch_async
Arshad Shaik
2

SWIFT 5.1 de la respuesta seleccionada para novatos

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!")
        }
    }
}

... en otro lugar de otra clase ...

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