Как передать NSDictionary с postNotificationName:object:

Я пытаюсь передать NSDictionary из UIView в UIViewController, используя NSNotificationCenter. Словарь работает нормально во время публикации уведомления, но в методе получения я не могу получить доступ ни к одному из объектов в словаре.

Вот как я создаю словарь и публикую уведомление...

itemDetails = [[NSDictionary alloc] initWithObjectsAndKeys:@"Topic 1", @"HelpTopic", nil];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HotSpotTouched" object:itemDetails];

В UIViewController я устанавливаю наблюдатель...

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(hotSpotMore:)
                                             name:@"HotSpotTouched"
                                           object:nil];

В целях тестирования hotSpotMore выглядит так...

- (void)hotSpotMore:(NSDictionary *)itemDetails{
      NSLog(@"%@", itemDetails);
      NSLog(@"%@", [itemDetails objectForKey:@"HelpTopic"]);    
}

Первый NSLog отлично работает, отображая содержимое словаря. Второй журнал выдает следующее исключение...

 [NSConcreteNotification objectForKey:]: unrecognized selector sent to instance 0x712b130

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

Заранее благодарю за любую помощь.

Джон


person user278859    schedule 08.11.2010    source источник


Ответы (3)


Первый NSLog отлично работает, отображая содержимое словаря. Второй журнал выдает следующее исключение...

Программа пытается вас обмануть, просто выглядит так, как будто это ваш словарь, потому что ваш словарь находится внутри уведомления. Из исключения вы можете видеть, что ваш объект на самом деле относится к классу с именем NSConcreteNotification.
Это потому, что аргумент метода уведомления всегда является объектом NSNotification. это будет работать:

- (void)hotSpotMore:(NSNotification *)notification {
      NSLog(@"%@", notification.object);
      NSLog(@"%@", [notification.object objectForKey:@"HelpTopic"]);    
}

просто как подсказка: объект обычно является объектом, который отправляет уведомление, вы должны отправить свой NSDictionary как userInfo.
Я думаю, что это улучшит ваш код, если вы сделаете это следующим образом:

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center postNotificationName:@"HotSpotTouched" object:self userInfo:itemDetails];


- (void)hotSpotMore:(NSNotification *)notification {
      NSLog(@"%@", notification.userInfo);
      NSLog(@"%@", [notification.userInfo objectForKey:@"HelpTopic"]);    
}

Параметр объекта используется для различения разных объектов, которые могут отправлять уведомления.
Предположим, у вас есть два разных объекта HotSpot, которые могут отправлять уведомления. Когда вы устанавливаете object в addObserver:selector:name:object:, вы можете добавить другого наблюдателя для каждого из объектов. Использование nil в качестве параметра объекта означает, что все уведомления должны быть получены, независимо от объекта, отправившего уведомление.

E.g:

FancyHotSpot *hotSpotA;
FancyHotSpot *hotSpotB;

// notifications from hotSpotA should call hotSpotATouched:
[[NSNotificationCenter defaultCenter] addObserver:self 
       selector:@selector(hotSpotATouched:) name:@"HotSpotTouched" 
       object:hotSpotA]; // only notifications from hotSpotA will be received

// notifications from hotSpotB should call hotSpotBTouched:
[[NSNotificationCenter defaultCenter] addObserver:self 
       selector:@selector(hotSpotBTouched:) name:@"HotSpotTouched" 
       object:hotSpotB]; // only notifications from hotSpotB will be received

// notifications from all objects should call anyHotSpotTouched:
[[NSNotificationCenter defaultCenter] addObserver:self 
       selector:@selector(anyHotSpotTouched:) name:@"HotSpotTouched" 
       object:nil]; // nil == “any object”, so all notifications with the name “HotSpotTouched” will be received


- (void)hotSpotATouched:(NSNotification *)n {
    // only gets notification of hot spot A
}

- (void)hotSpotBTouched:(NSNotification *)n {
    // only gets notification of hot spot B
}

- (void)anyHotSpotTouched:(NSNotification *)n {
    // catches all notifications
}
person Matthias Bauch    schedule 08.11.2010
comment
Здорово!! Спасибо, это сработало. Я вижу, что недостаточно внимательно прочитал разделы по программированию уведомлений. - person user278859; 08.11.2010
comment
+1 за то, что программа стала разумной и пытается вас обмануть :) - person Lescai Ionel; 13.10.2012
comment
Пост старый, но все равно очень ценный. Спасибо за это! Небольшое примечание: userInfo: возьмет NSDictionary. Если вы пытаетесь передать другой объект, вам придется вставить его в словарь. - person Alex; 17.10.2016

Это лучший способ передать данные словаря с помощью NSNotification.

Опубликовать уведомление:

 [[NSNotificationCenter defaultCenter] postNotificationName:@"Put Your Notification Name" object:self userInfo:"Pass your dictionary name"];

Добавьте Observer для обработки уведомления.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mydictionaryData:)  name:@"Put Your Notification Name" object:nil];

Поместите метод обработчика уведомлений.

- (void)mydictionaryData::(NSNotification*)notification{
   NSDictionary* userInfo = notification.userInfo;
   NSLog (@"Successfully received test notification! %@", userInfo);}

Надеюсь, это решение поможет вам

person Community    schedule 18.03.2013
comment
Я следовал этому коду, и он у меня не сработал, потому что тип аргумента должен быть NSNotification, а не NSDictionary. - person ericraio; 27.06.2013
comment
Пожалуйста, проверьте свой код. Если вы поделитесь своим кодом, я могу вам помочь. Вышеприведенный код работает в моих нескольких приложениях. - person Amit Singh; 12.02.2014
comment
У меня тоже не работает, sourceDictionary всегда пуст - person Travis M.; 20.03.2015

Метод, о котором говорит Матиас, и тот, который, я думаю, вы должны использовать, это

postNotificationName:object:userInfo:

Где object — отправитель, а userInfo — ваш словарь.

person Brabbeldas    schedule 02.02.2012