Kirim dan terima pesan melalui NSNotificationCenter di Objective-C?

610

Saya mencoba mengirim dan menerima pesan melalui NSNotificationCenterdi Objective-C. Namun, saya belum dapat menemukan contoh tentang cara melakukan ini. Bagaimana Anda mengirim dan menerima pesan NSNotificationCenter?

hichris123
sumber
Sangat bermanfaat, terima kasih. Satu hal, metode addObserver seharusnya tidak memiliki trailing semi colon setelah pemilih yang ditentukan (setidaknya itu menyebabkan pengecualian dalam versi saya ini). Saya mencoba mengedit kode di atas tetapi perubahan itu tidak diterima karena memformat masalah dalam kode asli.
Braunius
3
Ini hebat: cocoawithlove.com/2008/06/...
Aram Kocharyan
2
q ini terlalu mendasar dan luas, sedikit googleing akan bagus
Daij-Djan
Ini sangat mirip dengan pertanyaan terkait di sini: stackoverflow.com/questions/7896646/...
David Douglas
55
Saya merasa tidak masuk akal pertanyaan seperti ini ditutup tidak konstruktif ketika pengguna Stack Overflow telah dengan jelas berkomentar kegunaannya
Chet

Jawaban:

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

... di tempat lain di kelas lain ...

- (void) someMethod
{

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

}
dreamlax
sumber
2
Hanya ingin tahu di mana [NSNotificationCenter defaultCenter] dimaksudkan untuk ditempatkan. Apakah yang terbaik untuk menempatkannya di AppDelegate Anda?
fulvio
14
@Fulvio: Tergantung, jika Anda menerima atau memposting pemberitahuan yang berpotensi mempengaruhi semua bagian aplikasi Anda, masukkan ke AppDelegate Anda. Jika Anda menerima / mem-posting pemberitahuan yang hanya memengaruhi satu kelas, masukkan saja di kelas itu.
dreamlax
1
@dreamlax Truth, namun perlu diperhatikan karena pertanyaan ini sebagian besar dicari oleh devos baru yang membuat pendengar notifikasi tetap hidup lebih lama dari yang mereka butuhkan. Sekarang dengan arc Anda biasanya tidak menggunakan dealloc dan sebagai hasilnya beberapa orang mungkin berpikir mereka tidak perlu melepaskan pendengar.
Vive
7
Mungkin juga layak disebutkan bahwa [super dealloc]panggilan dalam metode dealloc tidak diizinkan di bawah ARC; sisanya baik-baik saja.
besok
1
Apa yang terjadi jika notifikasi menyala dan tidak ada pengamat? Apakah notifikasi hilang? Atau "diselamatkan" di suatu tempat yang siap dikirim ke pengamat baru (dibuat nanti)?
superpuccio
226

Untuk memperluas contoh dreamlax ... Jika Anda ingin mengirim data bersama dengan notifikasi

Dalam kode posting:

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

Dalam mengamati kode:

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

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
Michael Peterson
sumber
TestNotification harus tipe NSString. Apakah ini merupakan variabel NSNotification instan?
RomanHouse
1
Bisakah saya mengakses pengamat selfdalam metode acceptTestNotification?
mengapa
kenapa iya. acceptTestNotification adalah metode instance, dan Anda memiliki akses ke instance itu sendiri melalui diri di dalamnya.
Michael Peterson
Itu dia. Saya sedang mencari cara untuk mendapatkan UserInfo dari metode penerima.
hasan
Tampaknya semua gagasan pengamat itu tidak mencakup semua kasus. ini tidak berfungsi saat aplikasi. ditutup dan formulir notifikasi pusat notifikasi disadap. metode pengamat tidak dipanggil.
hasan
49

Yang ini membantu saya:

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

Sumber: http://www.smipple.net/snippet/Sounden/Simple%20NSNotificationCenter%20example

j7nn7k
sumber
Itu berhasil bagi saya! Terima kasih
Rakshitha Muranga Rodrigo
48

Ada juga kemungkinan menggunakan blok:

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

          // ...
     }];

Dokumentasi Apple

Xavi Gil
sumber
1
Ini adalah pembaruan yang bagus untuk jawaban saya yang sudah usang sekarang. Dengan pengantar atau ARC dan blok, pusat notifikasi jauh lebih mudah untuk ditangani.
dreamlax
5
Saya juga berpikir begitu, tetapi ternyata terlalu bagus untuk menjadi kenyataan. Dalam hal ini Anda harus mempertahankan pengamat yang addObserver kembali dan kemudian menghapusnya, yang membuatnya sama rumitnya dengan membuat metode baru, jika tidak lebih dari itu. Info lebih lanjut: toastmo.com/blog/2012/12/04/...
Andrew
42

jika Anda menggunakan NSNotificationCenter untuk memperbarui tampilan Anda, jangan lupa untuk mengirimkannya dari utas utama dengan menelepon dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});
Eiran
sumber
1
apakah pos pemberitahuan yang perlu muncul dari utas utama, atau hanya ketika Anda benar-benar memperbarui tampilan, yaitu, di dalam metode menerima pemberitahuan yang Anda kirim ke utas utama?
Crashalot
1
utas dari mana Anda mengirim notifikasi adalah utas yang menjalankan fungsinya, dan dengan demikian mencoba mengubah UI. Anda juga dapat menggunakan pengiriman ke utas utama di dalam fungsi, seperti yang Anda katakan: D. harus memiliki hasil yang sama, perheps itu bahkan lebih baik: D
eiran
1
@ Eiran, terima kasih banyak kawan, itu bekerja hanya setelah saya menulis di dalam dispatch_async
Arshad Shaik
2

SWIFT 5.1 dari jawaban yang dipilih untuk pemula

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!")
        }
    }
}

... di tempat lain di kelas lain ...

 func someMethod(){
        // All instances of TestClass will be notified
        NotificationCenter.default.post(name: "TestNotification", object: self)
 }
Maneesh M
sumber