137 votes

Comment passer un objet avec NSNotificationCenter ?

J'essaie de passer un objet de mon délégué d'application à un récepteur de notification dans une autre classe.

Je veux passer un nombre entier messageTotal . En ce moment, j'ai :

Dans le récepteur :

- (void) receiveTestNotification:(NSNotification *) notification
{
    if ([[notification name] isEqualToString:@"TestNotification"])
        NSLog (@"Successfully received the test notification!");
}

- (void)viewDidLoad {
    [super viewDidLoad];

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

Dans la classe qui fait la notification :

[UIApplication sharedApplication].applicationIconBadgeNumber = messageTotal;
[[NSNotificationCenter defaultCenter] postNotificationName:@"eRXReceived" object:self];

Mais je veux passer l'objet messageTotal à l'autre classe.

0 votes

Pour swift 2.0 et swift 3.0 stackoverflow.com/questions/36910965/

241voto

LearnCocos2D Points 43044

Vous devrez utiliser la variante "userInfo" et passer un objet NSDictionary qui contient le nombre entier messageTotal :

NSDictionary* userInfo = @{@"total": @(messageTotal)};

NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:@"eRXReceived" object:self userInfo:userInfo];

Du côté de la réception, vous pouvez accéder au dictionnaire userInfo comme suit :

-(void) receiveTestNotification:(NSNotification*)notification
{
    if ([notification.name isEqualToString:@"TestNotification"])
    {
        NSDictionary* userInfo = notification.userInfo;
        NSNumber* total = (NSNumber*)userInfo[@"total"];
        NSLog (@"Successfully received test notification! %i", total.intValue);
    }
}

0 votes

Merci, je suis en train de régler messageTotal à un badge sur un bouton UIB, savez-vous comment je peux rafraîchir le bouton avec le nouveau nombre de badges ? Le code pour afficher l'image dans viewDidLoad es UIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];

0 votes

Je ne sais pas pourquoi vous devez comparer le nom de la notification. Le mappage du nom devrait être effectué lorsque vous faites le addObserver(). La fonction receiveTestNotification ne devrait être appelée que lors de l'observation d'une notification spécifique.

1 votes

Johan, dans ce cas simple, vous avez raison, mais il est possible de faire en sorte que plusieurs notifications déclenchent le même gestionnaire.

95voto

David Douglas Points 1410

En me basant sur la solution fournie, j'ai pensé qu'il pourrait être utile de montrer un exemple de passage de votre propre objet de données personnalisé (que j'ai référencé ici en tant que "message" comme dans la question).

Classe A (expéditeur) :

YourDataObject *message = [[YourDataObject alloc] init];
// set your message properties
NSDictionary *dict = [NSDictionary dictionaryWithObject:message forKey:@"message"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationMessageEvent" object:nil userInfo:dict];

Classe B (récepteur) :

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(triggerAction:) name:@"NotificationMessageEvent" object:nil];
}

#pragma mark - Notification
-(void) triggerAction:(NSNotification *) notification
{
    NSDictionary *dict = notification.userInfo;
    YourDataObject *message = [dict valueForKey:@"message"];
    if (message != nil) {
        // do stuff here with your message data
    }
}

2 votes

Pourquoi cette réponse n'a pas plus de votes positifs ?! elle fonctionne parfaitement et n'est pas un hack !

4 votes

@Kairos parce qu'il n'est pas conçu pour être utilisé comme ça. le object param en postNotificationName doit être celui qui envoie cette notification.

2 votes

Oui, l'objet doit être transmis en tant que NSDictionary en utilisant la fonction userInfo param et la réponse acceptée ci-dessus a maintenant été modifiée pour le montrer.

33voto

Frouo Points 1348

Swift 5

func post() {
    NotificationCenter.default.post(name: Notification.Name("SomeNotificationName"), 
        object: nil, 
        userInfo:["key0": "value", "key1": 1234])
}

func addObservers() {
    NotificationCenter.default.addObserver(self, 
        selector: #selector(someMethod), 
        name: Notification.Name("SomeNotificationName"), 
        object: nil)
}

@objc func someMethod(_ notification: Notification) {
    let info0 = notification.userInfo?["key0"]
    let info1 = notification.userInfo?["key1"]
}

Bonus (que vous devriez absolument faire !) :

Remplacer Notification.Name("SomeNotificationName") con .someNotificationName :

extension Notification.Name {
    static let someNotificationName = Notification.Name("SomeNotificationName")
}

Remplacer "key0" y "key1" con Notification.Key.key0 y Notification.Key.key1 :

extension Notification {
  enum Key: String {
    case key0
    case key1
  }
}

Pourquoi devrais-je absolument le faire ? Pour éviter les erreurs typographiques coûteuses, pour profiter des renommages, pour profiter de l'utilisation de find etc...

27voto

Dan Beaulieu Points 12489

Version Swift 2

Comme @Johan Karlsson l'a souligné... Je le faisais mal. Voici la bonne façon d'envoyer et de recevoir des informations avec NSNotificationCenter.

Tout d'abord, nous examinons l'initialisateur de postNotificationName :

init(name name: String,
   object object: AnyObject?,
 userInfo userInfo: [NSObject : AnyObject]?)

source

Nous allons transmettre nos informations en utilisant le userInfo param. Le site [NSObject : AnyObject] est un vestige du Objectif-C . Ainsi, au pays de Swift, tout ce que nous devons faire est de transmettre un dictionnaire Swift dont les clés sont dérivées de NSObject et des valeurs qui peuvent être AnyObject .

Avec cette connaissance, nous créons un dictionnaire que nous allons passer dans la fonction object paramètre :

 var userInfo = [String:String]()
 userInfo["UserName"] = "Dan"
 userInfo["Something"] = "Could be any object including a custom Type."

Puis nous passons le dictionnaire dans notre paramètre objet.

Expéditeur

NSNotificationCenter.defaultCenter()
    .postNotificationName("myCustomId", object: nil, userInfo: userInfo)

Classe de récepteur

Tout d'abord, nous devons nous assurer que notre classe observe la notification.

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("btnClicked:"), name: "myCustomId", object: nil)   
}

Ensuite, nous pourrons recevoir notre dictionnaire :

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}

5voto

Muchab Points 309

Swift 5.1 Objet/type personnalisé

// MARK: - NotificationName
// Extending notification name to avoid string errors.
extension Notification.Name {
    static let yourNotificationName = Notification.Name("yourNotificationName")
}

// MARK: - CustomObject
class YourCustomObject {
    // Any stuffs you would like to set in your custom object as always.
    init() {}
}

// MARK: - Notification Sender Class
class NotificatioSenderClass {

     // Just grab the content of this function and put it to your function responsible for triggering a notification.
    func postNotification(){
        // Note: - This is the important part pass your object instance as object parameter.
        let yourObjectInstance = YourCustomObject()
        NotificationCenter.default.post(name: .yourNotificationName, object: yourObjectInstance)
    }
}

// MARK: -Notification  Receiver class
class NotificationReceiverClass: UIViewController {
    // MARK: - ViewController Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Register your notification listener
        NotificationCenter.default.addObserver(self, selector: #selector(didReceiveNotificationWithCustomObject), name: .yourNotificationName, object: nil)
    }

    // MARK: - Helpers
    @objc private func didReceiveNotificationWithCustomObject(notification: Notification){
        // Important: - Grab your custom object here by casting the notification object.
        guard let yourPassedObject = notification.object as? YourCustomObject else {return}
        // That's it now you can use your custom object
        //
        //

    }
      // MARK: - Deinit
  deinit {
      // Save your memory by releasing notification listener
      NotificationCenter.default.removeObserver(self, name: .yourNotificationName, object: nil)
    }

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X