Надсилання та отримання повідомлень через NSNotificationCenter в Objective-C?


610

Я намагаюся надсилати та отримувати повідомлення через NSNotificationCenterоб’єктив-С. Однак я не зміг знайти жодного прикладу, як це зробити. Як ви надсилаєте та отримуєте повідомлення NSNotificationCenter?


Дійсно дуже корисно, дякую. Одне, метод addObserver не повинен мати крапки з комою після вказаного селектора (принаймні, це спричинило виняток у моїй версії цього). Я спробував редагувати код вище, але зміна не була прийнята через проблеми форматування у вихідному коді.
Брауніус


2
цей q занадто базовий і широкий, трохи гуглінг мав би доброю для
бджіл

Це дуже схоже на пов'язане тут питання: stackoverflow.com/questions/7896646/…
Девід Дуглас

55
Я вважаю абсурдним питання, як це закрито не конструктивним, коли користувачі Stack Overflow так чітко прокоментували його корисність
Чет

Відповіді:


1019
@implementation TestClass

- (void) dealloc
{
    // If you don't remove yourself as an observer, the Notification Center
    // will continue to try and send notification objects to the deallocated
    // object.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (id) init
{
    self = [super init];
    if (!self) return nil;

    // Add this instance of TestClass as an observer of the TestNotification.
    // We tell the notification center to inform us of "TestNotification"
    // notifications using the receiveTestNotification: selector. By
    // specifying object:nil, we tell the notification center that we are not
    // interested in who posted the notification. If you provided an actual
    // object rather than nil, the notification center will only notify you
    // when the notification was posted by that particular object.

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

    return self;
}

- (void) receiveTestNotification:(NSNotification *) notification
{
    // [notification name] should always be @"TestNotification"
    // unless you use this method for observation of other notifications
    // as well.

    if ([[notification name] isEqualToString:@"TestNotification"])
        NSLog (@"Successfully received the test notification!");
}

@end

... десь в іншому класі ...

- (void) someMethod
{

    // All instances of TestClass will be notified
    [[NSNotificationCenter defaultCenter] 
        postNotificationName:@"TestNotification" 
        object:self];

}

2
Цікаво, куди має бути розміщений [NSNotificationCenter defaultCenter]. Краще розмістити його у своєму AppDelegate?
фульвіо

14
@Fulvio: Залежно, якщо ви отримуєте або розміщуєте повідомлення, які потенційно впливають на всі частини вашої програми, помістіть її у свій AppDelegate. Якщо ви отримуєте / публікуєте повідомлення, які стосуються лише одного класу, замістіть його у цьому класі.
dreamlax

1
@dreamlax Правда, однак, це варто помітити, оскільки це питання в основному шукають нові ios-розробники, які підтримують слухача сповіщень довше, ніж потрібно. Зараз з дугою ви зазвичай не використовуєте трансалок і, як результат, деякі можуть подумати, що вони не повинні звільняти слухача.
Vive

7
Можливо, варто також зазначити, що [super dealloc]виклик у методі dealloc не дозволений в ARC; решта - все добре.
tommys

1
Що станеться, якщо сповіщення буде запущено, а спостерігачів немає? Чи втрачено повідомлення? Або це "збережено" десь готове до відправки до нового спостерігача (створеного пізніше)?
superpuccio

226

Щоб розгорнутись на прикладі dreamlax ... Якщо ви хочете надіслати дані разом із повідомленням

У коді проводки:

NSDictionary *userInfo = 
[NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: 
                       @"TestNotification" object:nil userInfo:userInfo];

У дотриманні коду:

- (void) receiveTestNotification:(NSNotification *) notification {

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}

TestNotification повинен бути типу NSString. Це змінна екземпляр NSNotification?
RomanHouse

1
Чи можу я отримати доступ до спостерігача selfза методом receTestNotification?
чому

чому так. acceptTestNotification - це метод екземпляра, і ви маєте доступ до самого екземпляра через себе в ньому.
Майкл Петерсон

Це воно. Я шукав спосіб отримати UserInfo з методу отримання.
хасан

Здається, що вся ця ідея спостерігача не охоплює всіх випадків. це не спрацювало, коли додаток. було закрито, і форму повідомлень було отримано. метод спостерігача не викликається.
хасан

49

Цей мені допоміг:

// Add an observer that will respond to loginComplete
[[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(showMainMenu:) 
                                                 name:@"loginComplete" object:nil];


// Post a notification to loginComplete
[[NSNotificationCenter defaultCenter] postNotificationName:@"loginComplete" object:nil];


// the function specified in the same class where we defined the addObserver
- (void)showMainMenu:(NSNotification *)note {
    NSLog(@"Received Notification - Someone seems to have logged in"); 
}

Джерело: http://www.smipple.net/snippet/Sounden/Simple%20NSNotificationCenter%20example


Це працювало для мене! Спасибі
Ракшита Муранга Родріго

48

Також є можливість використання блоків:

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] 
     addObserverForName:@"notificationName" 
     object:nil
     queue:mainQueue
     usingBlock:^(NSNotification *notification)
     {
          NSLog(@"Notification received!");
          NSDictionary *userInfo = notification.userInfo;

          // ...
     }];

Документація Apple


1
Це хороше оновлення моєї відповіді, яке зараз досить застаріло. З введенням або ARC та блоками з центрами сповіщень набагато простіше впоратися.
dreamlax

5
Я теж так думав, але виявляється, що це занадто добре, щоб бути правдою. У цьому випадку вам слід утримати спостерігача, який addObserver повертається, а потім видалити це, що робить його таким же складним, як створення нового методу, якщо не більше. Більше інформації: toastmo.com/blog/2012/12/04/…
Андрій

42

якщо ви використовуєте NSNotificationCenter для оновлення перегляду, не забудьте надіслати його з головної нитки, зателефонувавши dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});

1
це повідомлення про появу повідомлень, яке має відбуватися з основного потоку, або саме тоді, коли ви фактично оновлюєте представлення даних, тобто всередині методу отримання повідомлення, який ви відправляєте в основний потік?
Crashalot

1
потік, з якого ви надсилаєте сповіщення, - це потік, який виконує функції, і, таким чином, намагається змінити інтерфейс користувача. ви також можете використовувати диспетчер до основної нитки всередині функцій, як ви сказали: D. повинен мати той самий результат, в перпепсі це ще краще: D
ейран

1
@eiran, спасибі, брате, це спрацювало лише після того, як я написав всередині dispatch_async
Аршад Шаїк

2

SWIFT 5.1 обраної відповіді для новачків

class TestClass {
    deinit {
        // If you don't remove yourself as an observer, the Notification Center
        // will continue to try and send notification objects to the deallocated
        // object.
        NotificationCenter.default.removeObserver(self)
    }

    init() {
        super.init()

        // Add this instance of TestClass as an observer of the TestNotification.
        // We tell the notification center to inform us of "TestNotification"
        // notifications using the receiveTestNotification: selector. By
        // specifying object:nil, we tell the notification center that we are not
        // interested in who posted the notification. If you provided an actual
        // object rather than nil, the notification center will only notify you
        // when the notification was posted by that particular object.

        NotificationCenter.default.addObserver(self, selector: #selector(receiveTest(_:)), name: NSNotification.Name("TestNotification"), object: nil)
    }

    @objc func receiveTest(_ notification: Notification?) {
        // [notification name] should always be @"TestNotification"
        // unless you use this method for observation of other notifications
        // as well.

        if notification?.name.isEqual(toString: "TestNotification") != nil {
            print("Successfully received the test notification!")
        }
    }
}

... десь в іншому класі ...

 func someMethod(){
        // All instances of TestClass will be notified
        NotificationCenter.default.post(name: "TestNotification", object: self)
 }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.