Cara meneruskan objek dengan NSNotificationCenter

129

Saya mencoba meneruskan objek dari delegasi aplikasi saya ke penerima notifikasi di kelas lain.

Saya ingin lulus bilangan bulat messageTotal. Sekarang saya punya:

Dalam Penerima:

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

Di kelas yang melakukan pemberitahuan:

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

Tapi saya ingin meneruskan objek messageTotalke kelas lain.

Jon
sumber
untuk swift 2.0 dan swift 3.0 stackoverflow.com/questions/36910965/…
Sahil

Jawaban:

235

Anda harus menggunakan varian "userInfo" dan meneruskan objek NSDictionary yang berisi integer messageTotal:

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

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

Di sisi penerima Anda dapat mengakses kamus userInfo sebagai berikut:

-(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);
    }
}
LearnCocos2D
sumber
Terima kasih, saya sedang mengatur messageTotallencana di UIButton, apakah Anda tahu bagaimana saya bisa menyegarkan tombol dengan jumlah lencana baru? Kode untuk menampilkan gambar viewDidLoadadalahUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
Jon
Saya tidak yakin mengapa Anda perlu membandingkan notification.name. Pemetaan nama harus dilakukan ketika Anda melakukan addObserver (). AcceptTestNotification hanya boleh dipanggil ketika mengamati pemberitahuan tertentu.
Johan Karlsson
1
Johan, dalam kasus sederhana ini Anda benar, tetapi dimungkinkan untuk memiliki beberapa notifikasi yang memicu handler yang sama
Lytic
93

Membangun pada solusi asalkan saya pikir mungkin membantu untuk menunjukkan contoh melewati objek data kustom Anda sendiri (yang saya rujuk di sini sebagai 'pesan' sesuai pertanyaan).

Kelas A (pengirim):

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

Kelas B (penerima):

- (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
    }
}
David Douglas
sumber
2
mengapa jawaban ini tidak memiliki lebih banyak suara positif ?! ini bekerja dengan sempurna dan bukan peretasan!
Reuben Tanner
4
@ Kairos karena tidak dirancang untuk digunakan seperti ini. yang objectparam di postNotificationName harus berarti satu yang mengirimkan pemberitahuan ini.
xi.lin
2
Ya objek harus dilewatkan sebagai NSDictionary menggunakan userInfoparam dan jawaban yang diterima di atas sekarang telah diedit untuk menunjukkan ini.
David Douglas
1
Ini sangat menyesatkan, mengapa jawaban itu memiliki begitu banyak upvotes? Ini harus dihapus. Setiap orang harus menggunakan userInfo yang dibuat persis untuk ini.
Shinnyx
Oke, terima kasih atas umpan baliknya ... Saya telah memperbarui jawaban untuk menggunakan userInfokamus sebagai cara untuk meneruskan data objek.
David Douglas
27

Versi Swift 2

Seperti yang ditunjukkan oleh @Johan Karlsson ... Saya salah melakukannya. Inilah cara yang tepat untuk mengirim dan menerima informasi dengan NSNotificationCenter.

Pertama, kita melihat inisialisasi untuk postNotificationName:

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

sumber

Kami akan meneruskan informasi kami menggunakan userInfoparam. The [NSObject : AnyObject]jenis adalah terus-alih dari Objective-C . Jadi, di tanah Swift, semua yang perlu kita lakukan adalah memasukkan kamus Swift yang memiliki kunci yang berasal dari NSObjectdan nilai-nilai yang dapat AnyObject.

Dengan pengetahuan itu kami membuat kamus yang akan kami sampaikan ke objectparameter:

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

Lalu kami meneruskan kamus ke parameter objek kami.

Pengirim

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

Kelas Penerima

Pertama, kita perlu memastikan kelas kita memperhatikan notifikasi

override func viewDidLoad() {
    super.viewDidLoad()

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

Maka kita dapat menerima kamus kami:

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}
Dan Beaulieu
sumber
Anda sebenarnya melanggar maksud penggunaan postNotificationName (). Tapi kamu tidak sendiri. Saya telah melihat banyak pengembang menggunakan parameter objek untuk mengirim objek pengguna. Argumen kedua, objek, disediakan untuk pengirim. Anda harus benar-benar menggunakan userInfo untuk mengirim semua jenis objek. Kalau tidak, Anda mungkin mengalami kecelakaan acak dll.
Johan Karlsson
25

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

Bonus (yang harus Anda lakukan!):

Ganti Notification.Name("SomeNotificationName")dengan .someNotificationName:

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

Ganti "key0"dan "key1"dengan Notification.Key.key0dan Notification.Key.key1:

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

Mengapa saya harus melakukan ini? Untuk menghindari kesalahan pengetikan yang mahal, nikmati penggantian nama, nikmati temukan penggunaan dll ...

kemari
sumber
Terima kasih. Rupanya memperluas Pemberitahuan. Nama mungkin tetapi tidak Pemberitahuan. 'Key' is not a member type of 'Notification'. Lihat di sini: https://ibb.co/hDQYbd2
alpennec
Terima kasih, sepertinya Keystruct telah dihapus sejak saat itu. Saya memperbarui jawabannya
frouo
1

Swift 5.1 Obyek / Jenis Kustom

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




}
Mussa Charles
sumber