Как передать объект с помощью NSNotificationCenter

Я пытаюсь передать объект из делегата моего приложения получателю уведомлений в другом классе.

Я хочу передать целое число messageTotal. Прямо сейчас у меня есть:

В приемнике:

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

В классе, который отправляет уведомление:

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

Но я хочу передать объект messageTotal другому классу.


person Jon    schedule 25.10.2011    source источник
comment
для быстрых 2.0 и быстрых 3.0 stackoverflow.com/questions/36910965/   -  person Sahil    schedule 19.01.2017


Ответы (5)


Вам нужно будет использовать вариант «userInfo» и передать объект NSDictionary, содержащий целое число messageTotal:

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

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

На принимающей стороне вы можете получить доступ к словарю userInfo следующим образом:

-(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);
    }
}
person LearnCocos2D    schedule 25.10.2011
comment
Спасибо, я устанавливаю messageTotal на значок на UIButton, вы знаете, как я могу обновить кнопку с новым количеством значков? Код для отображения изображения в viewDidLoad - UIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)]; - person Jon; 26.10.2011
comment
Я не уверен, почему вам нужно сравнивать notification.name. Сопоставление имени должно выполняться при выполнении addObserver (). ReceiveTestNotification должен вызываться только при наблюдении за конкретным уведомлением. - person Johan Karlsson; 17.02.2016
comment
Йохан, в этом простом случае вы правы, но возможно, чтобы несколько уведомлений запускали один и тот же обработчик. - person Lytic; 25.01.2017

Опираясь на предоставленное решение, я подумал, что было бы полезно показать пример передачи вашего собственного настраиваемого объекта данных (который я здесь назвал «сообщением» в соответствии с вопросом).

Класс A (отправитель):

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

Класс B (получатель):

- (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
    }
}
person David Douglas    schedule 21.06.2014
comment
почему за этот ответ не набралось больше голосов ?! он работает отлично и не является взломом! - person Reuben Tanner; 03.12.2014
comment
@Kairos, потому что он не предназначен для такого использования. параметр object в postNotificationName должен означать тот, который отправляет это уведомление. - person xi.lin; 09.07.2015
comment
Да, объект должен быть передан как NSDictionary с использованием параметра userInfo, и принятый выше ответ теперь отредактирован, чтобы показать это. - person David Douglas; 14.07.2015
comment
Это очень вводит в заблуждение, почему у этого ответа так много голосов? Это следует удалить. Каждый должен использовать userInfo, который создан именно для этого. - person Shinnyx; 20.10.2016
comment
Хорошо, спасибо за отзыв ... Я обновил ответ, чтобы использовать словарь userInfo в качестве способа передачи данных объекта. - person David Douglas; 25.10.2016
comment
@DavidDouglas в моем случае не срабатывает селектор › - person Krutarth Patel; 22.12.2016

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

Бонус (который обязательно стоит сделать!):

Замените Notification.Name("SomeNotificationName") на .someNotificationName:

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

Заменить "key0" и "key1" на Notification.Key.key0 и Notification.Key.key1:

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

Зачем мне обязательно это делать? Чтобы избежать дорогостоящих опечаток, переименовывайте, пользуйтесь поиском и т. Д.

person frouo    schedule 28.12.2016
comment
Спасибо. Очевидно, расширение Notification.Name возможно, но не Notification.Key. 'Key' is not a member type of 'Notification'. См. Здесь: https://ibb.co/hDQYbd2 - person alpennec; 10.07.2019
comment
Спасибо, похоже, с тех пор структура Key была удалена. Я обновляю ответ - person frouo; 10.07.2019

Версия Swift 2

Как заметил @Johan Karlsson ... Я делал это неправильно. Вот правильный способ отправки и получения информации с помощью NSNotificationCenter.

Сначала посмотрим на инициализатор postNotificationName:

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

источник

Мы будем передавать нашу информацию с помощью параметра userInfo. Тип [NSObject : AnyObject] унаследован от Objective-C. Итак, в стране Swift все, что нам нужно сделать, это передать словарь Swift, в котором есть ключи, производные от NSObject, и значения, которые могут быть AnyObject.

Обладая этими знаниями, мы создаем словарь, который передаем в параметр object:

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

Затем мы передаем словарь в параметр нашего объекта.

Отправитель

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

Класс получателя

Сначала нам нужно убедиться, что наш класс наблюдает за уведомлением.

override func viewDidLoad() {
    super.viewDidLoad()

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

Тогда мы можем получить наш словарь:

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}
person Dan Beaulieu    schedule 01.10.2015
comment
Фактически вы нарушаете предполагаемое использование postNotificationName (). Но вы не одиноки. Я видел, как многие разработчики использовали параметр объекта для отправки пользовательских объектов. Второй аргумент, объект, зарезервирован для отправителя. Вы действительно должны использовать userInfo для отправки всех видов объектов. В противном случае вы можете столкнуться со случайными сбоями и т. Д. - person Johan Karlsson; 17.02.2016

Пользовательский объект / тип Swift 5.1

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




}

person Mussa Charles    schedule 04.03.2020