Envoyer et recevoir des messages via NSNotificationCenter dans Objective-C?

610

J'essaie d'envoyer et de recevoir des messages via NSNotificationCenterObjective-C. Cependant, je n'ai pas pu trouver d'exemples sur la façon de procéder. Comment envoyez-vous et recevez-vous les messages NSNotificationCenter?

hichris123
la source
Vraiment très utile, merci. Une chose, la méthode addObserver ne devrait pas avoir le point-virgule de fin après le sélecteur spécifié (au moins, cela a provoqué une exception dans ma version de ceci). J'ai essayé de modifier le code ci-dessus mais la modification n'a pas été acceptée en raison de problèmes de formatage dans le code d'origine.
Braunius
3
C'était génial: cocoawithlove.com/2008/06/…
Aram Kocharyan
2
ce q est beaucoup trop basique et large, un peu de google aurait été bien
Daij-Djan
Ceci est très similaire à une question connexe ici: stackoverflow.com/questions/7896646/…
David Douglas
55
Je trouve absurde qu'une question comme celle-ci soit fermée et non constructive lorsque les utilisateurs de Stack Overflow ont si clairement commenté son utilité
Chet

Réponses:

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

... ailleurs dans une autre classe ...

- (void) someMethod
{

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

}
dreamlax
la source
2
Je me demande simplement où [NSNotificationCenter defaultCenter] est censé être placé. Est-il préférable de le placer dans votre AppDelegate?
fulvio
14
@Fulvio: Cela dépend, si vous recevez ou publiez des notifications qui affectent potentiellement toutes les parties de votre application, placez-les dans votre AppDelegate. Si vous recevez / publiez des notifications qui n'affectent qu'une seule classe, placez-les à la place dans cette classe.
dreamlax
1
@dreamlax Truth, mais il convient de le noter, car cette question est principalement recherchée par les nouveaux développeurs ios qui gardent l'écouteur de notification en vie plus longtemps que nécessaire. Maintenant, avec arc, vous n'utilisez généralement pas dealloc et, par conséquent, certains peuvent penser qu'ils n'ont pas à libérer l'auditeur.
Vive
7
Il peut également être utile de mentionner que l' [super dealloc]appel dans la méthode dealloc n'est pas autorisé sous ARC; le reste est tout bon.
tommys
1
Que se passe-t-il si la notification se déclenche et qu'il n'y a pas d'observateurs? La notification est-elle perdue? Ou est-il «enregistré» quelque part prêt à être expédié à un nouvel observateur (créé plus tard)?
superpuccio
226

Pour développer l'exemple de dreamlax ... Si vous souhaitez envoyer des données avec la notification

Dans le code d'affichage:

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

En observant le code:

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

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
Michael Peterson
la source
TestNotification doit être de type NSString. S'agit-il d'une variable d'instance NSNotification?
RomanHouse
1
Puis-je accéder à l'observateur selfdans la méthode receiveTestNotification?
pourquoi le
pourquoi oui. receiveTestNotification est une méthode d'instance, et vous avez accès à l'instance elle-même via self en son sein.
Michael Peterson
C'est ça. Je cherchais un moyen d'obtenir les UserInfo à partir de la méthode du récepteur.
hasan
Il semble que toute cette idée d'observateur ne couvre pas tous les cas. cela ne fonctionnait pas lorsque l'application. a été fermé et un formulaire de notification utilisé par le centre de notification a été utilisé. la méthode observateur n'est pas appelée.
hasan
49

Celui-ci m'a aidé:

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

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

j7nn7k
la source
Cela a fonctionné pour moi! Merci
Rakshitha Muranga Rodrigo
48

Il y a aussi la possibilité d'utiliser des blocs:

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

          // ...
     }];

Documentation d'Apple

Xavi Gil
la source
1
Ceci est une bonne mise à jour de ma réponse qui est assez obsolète maintenant. Avec l'introduction ou ARC et les blocs, les centres de notification sont beaucoup plus faciles à gérer.
dreamlax
5
Je le pensais aussi, mais il s'avère que c'est trop beau pour être vrai. Dans ce cas, vous devez conserver l'observateur renvoyé par addObserver, puis le supprimer, ce qui complique la création d'une nouvelle méthode, sinon davantage. Plus d'infos: toastmo.com/blog/2012/12/04/…
Andrew
42

si vous utilisez NSNotificationCenter pour mettre à jour votre vue, n'oubliez pas de l'envoyer depuis le thread principal en appelant dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});
eiran
la source
1
est-ce le message de notification qui doit se produire à partir du thread principal, ou juste lorsque vous mettez à jour la vue, c'est-à-dire à l'intérieur de la méthode recevant la notification que vous envoyez au thread principal?
Crashalot
1
le thread à partir duquel vous envoyez la notification est le thread exécutant les fonctions et essayant ainsi de changer l'interface utilisateur. vous pouvez également utiliser la répartition vers le thread principal à l'intérieur des fonctions, comme vous l'avez dit: D. devrait avoir le même résultat, peut-être que c'est encore mieux: D
eiran
1
@eiran, merci beaucoup mon frère, cela n'a fonctionné qu'après avoir écrit dans dispatch_async
Arshad Shaik
2

SWIFT 5.1 de la réponse sélectionnée pour les débutants

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

... ailleurs dans une autre classe ...

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