Як передавати об’єкт за допомогою NSNotificationCenter


129

Я намагаюся передати об’єкт від свого делегата додатку до приймача сповіщень іншого класу.

Я хочу передати ціле число 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іншому класу.


для swift 2.0 та swift 3.0 stackoverflow.com/questions/36910965/…
Сахіль

Відповіді:


235

Вам доведеться скористатися варіантом "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);
    }
}

Дякую, я встановлюю messageTotalзначок на UIButton, чи знаєте ви, як я можу оновити кнопку за допомогою нового числа значків? Код для відображення зображення viewDidLoadєUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
Jon

Я не впевнений, чому вам потрібно порівняти ім'я notification.name. Відображення імені повинно виконуватися, коли ви робите addObserver (). Повідомлення ReceTestNotification слід викликати лише при дотриманні конкретного повідомлення.
Йохан Карлссон

1
Йохане, у цьому простому випадку ти маєш рацію, але можливе отримання декількох сповіщень про те, що той самий обробник
Lytic

93

Спираючись на рішення, я подумав, що може бути корисним показати приклад передачі вашого власного об’єкта даних (на який я посилався тут як «повідомлення» відповідно до питання).

Клас А (відправник):

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

Клас В (приймач):

- (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
чому ця відповідь не має більше підстав ?! він працює чудово і не є хак!
Reuben Tanner

4
@Kairos, оскільки він не розроблений для подібного використання. objectпари в postNotificationName повинен означає той , який відправити повідомлення про втрату чинності.
xi.lin

2
Так, об'єкт повинен бути переданий як NSDictionary за допомогою парамеру, userInfoі прийнята відповідь вище була відредагована, щоб показати це.
Девід Дуглас

1
Це дуже оманливо, чому ця відповідь має стільки результатів? Це слід видалити. Усі повинні використовувати userInfo, створений саме для цього.
Shinnyx

Добре, дякую за відгук ... Я оновив відповідь, щоб використовувати userInfoсловник як спосіб передачі даних об'єкта.
Девід Дуглас,

27

Версія 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)
}

Ви фактично порушуєте призначене використання PostNotificationName (). Але ви не самотні. Я бачив багатьох розробників, які використовують параметр об'єкта для надсилання об’єктів користувача. Другий аргумент, об’єкт, зарезервований для відправника. Ви повинні дійсно користувачеві користувачевіІнфо надсилати всі види об’єктів. В іншому випадку ви можете зіткнутися з випадковими аваріями і т. Д.
Йохан Карлссон,

25

Швидкий 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
  }
}

Чому я точно повинен це робити? Щоб уникнути дорогих помилок друку, насолоджуйтесь перейменуванням, насолоджуйтесь пошуком використання тощо ...


Дякую. Мабуть, розширення Notification.Name можливе, але не Notification.Key. 'Key' is not a member type of 'Notification'. Дивіться тут: https://ibb.co/hDQYbd2
alpennec

Дякую, здається, Keyструктура з цього часу була видалена. Я
оновлюю

1

Швидкий 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)
    }




}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.