Gửi và nhận tin nhắn qua NSNotificationCenter trong Objective-C?


610

Tôi đang cố gắng gửi và nhận tin nhắn NSNotificationCentertrong Objective-C. Tuy nhiên, tôi không thể tìm thấy bất kỳ ví dụ nào về cách thực hiện việc này. Làm thế nào để bạn gửi và nhận tin nhắn thông qua NSNotificationCenter?


Thực sự rất hữu ích, cảm ơn. Một điều, phương thức addObserver không nên có dấu chấm phẩy sau bộ chọn được chỉ định (ít nhất là nó gây ra một ngoại lệ trong phiên bản này của tôi). Tôi đã thử chỉnh sửa mã ở trên nhưng thay đổi không được chấp nhận do các vấn đề định dạng trong mã gốc.
Braunius

3
Điều này thật tuyệt: cocoawithlove.com/2008/06/ Lời
Aram Kocharyan

2
q này quá cơ bản và rộng, một chút google sẽ trở nên tốt
Daij-Djan

Điều này rất giống với một câu hỏi liên quan ở đây: stackoverflow.com/questions/7896646/ Kẻ
David Douglas

55
Tôi thấy thật vô lý khi một câu hỏi như thế này bị đóng lại không mang tính xây dựng khi người dùng Stack Overflow đã nhận xét rất rõ ràng về tính hữu dụng của nó
Chet

Câu trả lời:


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

... ở một nơi khác trong lớp khác ...

- (void) someMethod
{

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

}

2
Chỉ cần tự hỏi [NSNotificationCenter defaultCenter] được đặt ở đâu. Là tốt nhất để đặt nó trong AppDelegate của bạn?
Fulvio

14
@Fulvio: Tùy thuộc, nếu bạn đang nhận hoặc đăng thông báo có khả năng ảnh hưởng đến tất cả các phần trong ứng dụng của bạn, hãy đặt nó trong AppDelegate của bạn. Nếu bạn đang nhận / đăng thông báo chỉ ảnh hưởng đến một lớp duy nhất, thay vào đó hãy đặt nó trong lớp đó.
dreamlax

1
@dreamlax Sự thật, tuy nhiên nó đáng chú ý vì câu hỏi này chủ yếu được tìm kiếm bởi các nhà phát triển ios mới, những người giữ cho người nghe thông báo sống lâu hơn họ cần. Bây giờ với arc bạn thường không sử dụng dealloc và kết quả là một số người có thể nghĩ rằng họ không phải giải phóng người nghe.
Vive

7
Cũng có thể đáng nói rằng [super dealloc]cuộc gọi trong phương thức dealloc không được phép theo ARC; phần còn lại là tốt
tommys

1
Điều gì xảy ra nếu thông báo kích hoạt và không có người quan sát? Là thông báo bị mất? Hay nó được "lưu" ở đâu đó sẵn sàng để được chuyển đến một người quan sát mới (được tạo sau)?
superpuccio 27/2/2015

226

Để mở rộng theo ví dụ của dreamlax ... Nếu bạn muốn gửi dữ liệu cùng với thông báo

Trong mã đăng bài:

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

Trong việc quan sát mã:

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

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

TestNotification phải là loại NSString. Đây có phải là một biến NSNotification không?
RomanHouse

1
Tôi có thể truy cập trình quan sát selftrong phương thức receiveTestNotification không?
tại sao

tại sao có. receiveTestNotification là một phương pháp dụ, và bạn có quyền truy cập vào các trường hợp riêng của mình thông qua tự bên trong nó.
Michael Peterson

Đó là nó. Tôi đang tìm cách để có được UserInfo từ phương thức nhận.
hasan

Dường như tất cả những ý tưởng quan sát viên không bao gồm tất cả các trường hợp. Điều này không hoạt động khi ứng dụng. đã bị đóng và một hình thức thông báo trung tâm thông báo đã khai thác. phương pháp quan sát viên không được gọi.
hasan

49

Điều này đã giúp tôi:

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

Nguồn: http://www.sm Knob.net/snippet/Sounden/Simple%20NSNotificationCenter%20example


Điều đó đã làm việc cho tôi! Cảm ơn
Rakshitha Muranga Rodrigo

48

Ngoài ra còn có khả năng sử dụng các khối:

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

          // ...
     }];

Tài liệu của Apple


1
Đây là một bản cập nhật tốt cho câu trả lời của tôi hiện đã khá lỗi thời. Với phần giới thiệu hoặc ARC và các khối, các trung tâm thông báo sẽ dễ xử lý hơn nhiều.
dreamlax

5
Tôi cũng nghĩ vậy, nhưng hóa ra nó quá tốt để trở thành sự thật. Trong trường hợp này, bạn phải giữ lại trình quan sát mà addObserver trả về và sau đó loại bỏ điều đó, điều này làm cho nó phức tạp như việc tạo một phương thức mới, nếu không muốn nói là như vậy. Thêm thông tin: toastmo.com/blog/2012/12/04/ khăn
Andrew

42

nếu bạn đang sử dụng NSNotificationCenter để cập nhật điểm của bạn, đừng quên gửi nó từ chủ đề chính bằng cách gọi dispatch_async:

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

1
Đây có phải là bài thông báo cần xuất hiện từ luồng chính hay chỉ khi bạn thực sự cập nhật khung nhìn, tức là bên trong phương thức nhận thông báo bạn gửi đến luồng chính?
Crashalot

1
chuỗi bạn gửi thông báo từ đó là luồng chạy các chức năng và do đó cố gắng thay đổi giao diện người dùng. bạn cũng có thể sử dụng công văn đến luồng chính bên trong các hàm, giống như bạn đã nói: D. sẽ có kết quả tương tự, làm cho nó thậm chí còn tốt hơn: D
eiran

1
@eiran, cảm ơn bạn rất nhiều bạn, nó chỉ hoạt động sau khi tôi viết bên trong Clark_async
Clark_async

2

SWift 5.1 của câu trả lời được chọn cho người mới

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

... ở một nơi khác trong lớp khác ...

 func someMethod(){
        // All instances of TestClass will be notified
        NotificationCenter.default.post(name: "TestNotification", object: self)
 }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.