¿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?


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


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];

}

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"];
}

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


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


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];
});

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)
 }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.