So übergeben Sie ein Objekt mit NSNotificationCenter

129

Ich versuche, ein Objekt von meinem App-Delegaten an einen Benachrichtigungsempfänger in einer anderen Klasse zu übergeben.

Ich möchte eine Ganzzahl übergeben messageTotal. Gerade habe ich:

Im Empfänger:

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

In der Klasse, die die Benachrichtigung ausführt:

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

Aber ich möchte das Objekt messageTotalan die andere Klasse übergeben.

Jon
quelle
für schnelle 2.0 und schnelle 3.0 stackoverflow.com/questions/36910965/…
Sahil

Antworten:

235

Sie müssen die Variante "userInfo" verwenden und ein NSDictionary-Objekt übergeben, das die Ganzzahl messageTotal enthält:

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

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

Auf der Empfangsseite können Sie wie folgt auf das userInfo-Wörterbuch zugreifen:

-(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);
    }
}
LearnCocos2D
quelle
Danke, ich setze messageTotalein Abzeichen auf einem UIButton. Wissen Sie, wie ich die Schaltfläche mit der neuen Abzeichenanzahl aktualisieren kann? Der Code, um das Bild anzuzeigen, viewDidLoadistUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
Jon
Ich bin nicht sicher, warum Sie den Benachrichtigungsnamen vergleichen müssen. Die Zuordnung des Namens sollte beim Hinzufügen von addObserver () erfolgen. Die receiveTestNotification sollte nur aufgerufen werden, wenn eine bestimmte Benachrichtigung beobachtet wird.
Johan Karlsson
1
Johan, in diesem einfachen Fall sind Sie richtig, aber es ist möglich, dass mehrere Benachrichtigungen denselben Handler auslösen
Lytic
93

Aufbauend auf der bereitgestellten Lösung hielt ich es für hilfreich, ein Beispiel zu zeigen, das Ihr eigenes benutzerdefiniertes Datenobjekt übergibt (auf das ich hier gemäß Frage als "Nachricht" verwiesen habe).

Klasse A (Absender):

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

Klasse B (Empfänger):

- (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
    }
}
David Douglas
quelle
2
Warum hat diese Antwort nicht mehr positive Stimmen?! es funktioniert perfekt und ist kein Hack!
Reuben Tanner
4
@ Kairos, weil es nicht so konzipiert ist. Der objectParameter in postNotificationName sollte denjenigen bedeuten, der diese Benachrichtigung sendet.
xi.lin
2
Ja, das Objekt sollte mit dem userInfoParameter als NSDictionary übergeben werden, und die oben akzeptierte Antwort wurde jetzt bearbeitet, um dies anzuzeigen.
David Douglas
1
Das ist sehr irreführend. Warum hat diese Antwort so viele positive Stimmen? Dies sollte gelöscht werden. Jeder sollte userInfo verwenden, das genau dafür erstellt wurde.
Shinnyx
Ok, danke für das Feedback ... Ich habe die Antwort aktualisiert, um das userInfoWörterbuch als Übergabe der Objektdaten zu verwenden.
David Douglas
27

Swift 2 Version

Wie @Johan Karlsson betonte ... Ich habe es falsch gemacht. Hier ist der richtige Weg, um Informationen mit NSNotificationCenter zu senden und zu empfangen.

Zuerst betrachten wir den Initialisierer für postNotificationName:

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

Quelle

Wir geben unsere Informationen mit dem userInfoParameter weiter. Der [NSObject : AnyObject]Typ ist ein Überbleibsel von Objective-C . In Swift Land müssen wir also nur ein Swift-Wörterbuch übergeben, das Schlüssel enthält, von denen abgeleitet wird, NSObjectund Werte, die sein können AnyObject.

Mit diesem Wissen erstellen wir ein Wörterbuch, das wir an den objectParameter übergeben:

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

Dann übergeben wir das Wörterbuch an unseren Objektparameter.

Absender

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

Empfängerklasse

Zuerst müssen wir sicherstellen, dass unsere Klasse die Benachrichtigung beobachtet

override func viewDidLoad() {
    super.viewDidLoad()

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

Dann können wir unser Wörterbuch erhalten:

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}
Dan Beaulieu
quelle
Sie verstoßen tatsächlich gegen die beabsichtigte Verwendung von postNotificationName (). Aber du bist nicht allein. Ich habe viele Entwickler gesehen, die den Objektparameter zum Senden von Benutzerobjekten verwendet haben. Das zweite Argument, das Objekt, ist dem Absender vorbehalten. Sie sollten die userInfo wirklich verwenden, um alle Arten von Objekten zu senden. Andernfalls könnten zufällige Abstürze usw. auftreten
Johan Karlsson
25

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 (das sollten Sie unbedingt tun!):

Ersetzen Notification.Name("SomeNotificationName")durch .someNotificationName:

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

Ersetzen "key0"und "key1"durch Notification.Key.key0und Notification.Key.key1:

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

Warum sollte ich das definitiv tun? Um kostspielige Tippfehler zu vermeiden, genießen Sie das Umbenennen, die Verwendung usw.

frouo
quelle
Vielen Dank. Anscheinend ist die Erweiterung von Notification.Name möglich, Notification.Key jedoch nicht. 'Key' is not a member type of 'Notification'. Siehe hier: https://ibb.co/hDQYbd2
Alpennec
Vielen Dank, es scheint, dass Keystruct seitdem entfernt wurde. Ich aktualisiere die Antwort
vom
1

Swift 5.1 Benutzerdefiniertes Objekt / Typ

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




}
Mussa Charles
quelle