Cách truyền đối tượng với NSNotificationCenter


129

Tôi đang cố gắng chuyển một đối tượng từ đại biểu ứng dụng của mình sang một người nhận thông báo trong một lớp khác.

Tôi muốn vượt qua số nguyên messageTotal. Ngay bây giờ tôi có:

Trong máy thu:

- (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];

Trong lớp đang thực hiện thông báo:

[UIApplication sharedApplication].applicationIconBadgeNumber = messageTotal;
[[NSNotificationCenter defaultCenter] postNotificationName:@"eRXReceived" object:self];

Nhưng tôi muốn truyền đối tượng messageTotalcho lớp khác.


cho swift 2.0 và swift 3.0 stackoverflow.com/questions
6910965 / từ

Câu trả lời:


235

Bạn sẽ phải sử dụng biến thể "userInfo" và vượt qua một đối tượng NSDipedia có chứa số nguyên messageTotal:

NSDictionary* userInfo = @{@"total": @(messageTotal)};

NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:@"eRXReceived" object:self userInfo:userInfo];

Ở đầu nhận, bạn có thể truy cập từ điển userInfo như sau:

-(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);
    }
}

Cảm ơn, tôi đang đặt messageTotalhuy hiệu trên UIButton, bạn có biết làm thế nào tôi có thể làm mới nút bằng số huy hiệu mới không? Mã để hiển thị hình ảnh trong viewDidLoadUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
Jon

Tôi không chắc tại sao bạn cần so sánh thông báo.name. Ánh xạ của tên phải được thực hiện khi bạn thực hiện addObserver (). Chỉ nên gọi receiveTestNotification khi quan sát một thông báo cụ thể.
Johan Karlsson

1
Johan, trong trường hợp đơn giản này, bạn đã đúng, nhưng có thể có nhiều thông báo kích hoạt cùng một trình xử lý
Lytic

93

Dựa trên giải pháp được cung cấp Tôi nghĩ rằng có thể hữu ích khi hiển thị một ví dụ truyền đối tượng dữ liệu tùy chỉnh của riêng bạn (mà tôi đã tham chiếu ở đây dưới dạng 'tin nhắn' theo câu hỏi).

Lớp A (người gửi):

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

Lớp B (người nhận):

- (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
Tại sao câu trả lời này không có nhiều upvote?! Nó hoạt động hoàn hảo và không phải là một hack!
Reuben Tanner

4
@Kairos vì nó không được thiết kế để sử dụng như thế này. các objecttrong param postNotificationName nên có nghĩa là một trong đó gửi thông báo này.
xi.lin

2
Có, đối tượng nên được thông qua dưới dạng NSDipedia bằng cách sử dụng userInfoparam và câu trả lời được chấp nhận ở trên hiện đã được chỉnh sửa để hiển thị điều này.
David Douglas

1
Điều này rất sai lệch, tại sao câu trả lời đó có rất nhiều upvote? Điều này nên được xóa. Mọi người nên sử dụng userInfo được tạo chính xác cho việc này.
Shinnyx

Ok, cảm ơn vì đã phản hồi ... Tôi đã cập nhật câu trả lời để sử dụng userInfotừ điển làm cách truyền dữ liệu của đối tượng.
David Douglas

27

Phiên bản Swift 2

Như @Johan Karlsson đã chỉ ra ... Tôi đã làm sai. Đây là cách thích hợp để gửi và nhận thông tin với NSNotificationCenter.

Đầu tiên, chúng tôi xem xét trình khởi tạo cho postNotificationName:

init(name name: String,
   object object: AnyObject?,
 userInfo userInfo: [NSObject : AnyObject]?)

nguồn

Chúng tôi sẽ chuyển thông tin của chúng tôi bằng cách sử dụng userInfoparam. Các [NSObject : AnyObject]loại là một tổ chức giao từ Objective-C . Vì vậy, ở vùng đất Swift, tất cả những gì chúng ta cần làm là chuyển vào một từ điển Swift có các khóa được lấy từ NSObjectvà các giá trị có thể có AnyObject.

Với kiến ​​thức đó, chúng tôi tạo ra một từ điển mà chúng ta sẽ chuyển vào objecttham số:

 var userInfo = [String:String]()
 userInfo["UserName"] = "Dan"
 userInfo["Something"] = "Could be any object including a custom Type."

Sau đó, chúng tôi chuyển từ điển vào tham số đối tượng của chúng tôi.

Người gửi

NSNotificationCenter.defaultCenter()
    .postNotificationName("myCustomId", object: nil, userInfo: userInfo)

Lớp nhận

Đầu tiên chúng ta cần đảm bảo rằng lớp chúng ta đang quan sát thông báo

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("btnClicked:"), name: "myCustomId", object: nil)   
}
    

Sau đó, chúng tôi có thể nhận được từ điển của chúng tôi:

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}

Bạn đang thực sự vi phạm mục đích sử dụng của postNotificationName (). Nhưng bạn không cô đơn. Tôi đã thấy nhiều nhà phát triển sử dụng tham số đối tượng để gửi đối tượng người dùng. Đối số thứ hai, đối tượng, được dành riêng cho người gửi. Bạn thực sự nên sử dụng userInfo để gửi tất cả các loại đối tượng. Nếu không, bạn có thể gặp phải sự cố ngẫu nhiên, v.v.
Johan Karlsson

25

Swift 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"]
}

Phần thưởng (mà bạn chắc chắn nên làm!):

Thay thế Notification.Name("SomeNotificationName")bằng .someNotificationName:

extension Notification.Name {
    static let someNotificationName = Notification.Name("SomeNotificationName")
}

Thay thế "key0""key1"bằng Notification.Key.key0Notification.Key.key1:

extension Notification {
  enum Key: String {
    case key0
    case key1
  }
}

Tại sao tôi chắc chắn nên làm điều này? Để tránh các lỗi đánh máy tốn kém, hãy tận hưởng việc đổi tên, tận hưởng việc sử dụng, v.v ...


Cảm ơn. Rõ ràng việc mở rộng Thông báo. Có thể nhưng không phải Thông báo.Key. 'Key' is not a member type of 'Notification'. Xem tại đây: https://ibb.co/hDQYbd2
alpennec

Cảm ơn bạn, có vẻ như Keystruct đã bị xóa từ đó. Tôi đang cập nhật câu trả lời
frouo

1

Đối tượng / Loại tùy chỉnh Swift 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)
    }




}
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.