NSNotificationCenter ile nesne nasıl geçirilir


129

Uygulama temsilcimden başka bir sınıftaki bir bildirim alıcısına bir nesne geçirmeye çalışıyorum.

Tamsayı geçirmek istiyorum messageTotal. Şu anda var:

Alıcıda:

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

Bildirimi yapan sınıfta:

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

Ama nesneyi messageTotaldiğer sınıfa geçirmek istiyorum .


swift 2.0 ve swift 3.0 için stackoverflow.com/questions/36910965/…
Sahil

Yanıtlar:


235

"UserInfo" varyantını kullanmanız ve messageTotal tamsayısını içeren bir NSDictionary nesnesi iletmeniz gerekir:

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

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

Alıcı uçta userInfo sözlüğüne aşağıdaki şekilde erişebilirsiniz:

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

Teşekkürler, messageTotalbir UIB düğmesinde bir rozet ayarlıyorum , düğmeyi yeni rozet sayısıyla nasıl yenileyebileceğimi biliyor musunuz? Görüntünün görüntülenmesi için kod viewDidLoadolanUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
Jon

Bildirim adını neden karşılaştırmanız gerektiğinden emin değilim. AddObserver () komutunu yaptığınızda adın eşlenmesi gerçekleştirilmelidir. GetTestNotification yalnızca belirli bir bildirim gözlemlenirken çağrılmalıdır.
Johan Karlsson

1
Johan, bu basit durumda haklısın, ancak birden fazla bildirimin aynı işleyiciyi tetiklemesi mümkündür
Lytic

93

Sağlanan çözüme dayanarak, kendi özel veri nesnenizi geçiren bir örnek göstermenin yararlı olabileceğini düşündüm (burada soru başına 'mesaj' olarak referans verdim).

A Sınıfı (gönderen):

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

Sınıf B (alıcı):

- (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
neden bu yanıtın daha fazla olumlu oyu yok ?! mükemmel çalışıyor ve bir hack değil!
Reuben Tanner

4
@Kairos çünkü böyle kullanmak için tasarlanmamıştır. objectparam içinde postNotificationName bu bildirimi göndermek tane anlam olmalıdır.
xi.lin

2
Evet, nesne userInfoparam kullanılarak bir NSDictionary olarak aktarılmalıdır ve yukarıdaki kabul edilen cevap bunu göstermek için şimdi düzenlenmiştir.
David Douglas

1
Bu çok yanıltıcı, neden bu yanıtın bu kadar çok olumlu oyu var? Bu silinmelidir. Herkes tam olarak bunun için oluşturulmuş userInfo kullanmalıdır.
Shinnyx

Tamam, geri bildirim için teşekkürler ... userInfoNesnenin verilerini iletmenin yolu olarak sözlüğü kullanmak için cevabı güncelledim .
David Douglas

27

Swift 2 Sürümü

@Johan Karlsson'ın belirttiği gibi ... Yanlış yapıyordum. NSNotificationCenter ile bilgi göndermenin ve almanın doğru yolu burada.

İlk olarak, postNotificationName için başlatıcıya bakarız:

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

kaynak

Bilgilerimizi userInfoparametresini kullanarak aktaracağız. [NSObject : AnyObject]Tip bir önceki dönemin dan Objective-C . Yani, Swift ülkesinde tek yapmamız gereken, anahtarlardan türetilen bir Swift sözlüğünü geçmek.NSObject ve olabilecek değerlere sahipAnyObject .

Bu bilgiyle, objectparametreye aktaracağımız bir sözlük oluşturuyoruz :

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

Daha sonra sözlüğü nesne parametremize aktarıyoruz.

Gönderen

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

Alıcı Sınıfı

Öncelikle sınıfımızın bildirimi gözlemlediğinden emin olmalıyız.

override func viewDidLoad() {
    super.viewDidLoad()

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

Sonra sözlüğümüzü alabiliriz:

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

Aslında postNotificationName () öğesinin kullanım amacını ihlal ediyorsunuz. Ama sen yalnız değilsin. Kullanıcı nesnelerini göndermek için nesne parametresini kullanan birçok geliştirici gördüm. İkinci argüman olan nesne, gönderene ayrılmıştır. Her tür nesneyi göndermek için userInfo'yu gerçekten kullanmalısınız. Aksi takdirde rastgele çökmeler vb.
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"]
}

Bonus (kesinlikle yapmanız gereken!):

Değiştir Notification.Name("SomeNotificationName")ile .someNotificationName:

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

Değiştir "key0"ve "key1"ile Notification.Key.key0ve Notification.Key.key1:

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

Bunu neden kesinlikle yapmalıyım? Maliyetli yazım hatası hatalarını önlemek için, yeniden adlandırmanın keyfini çıkarın, kullanımın keyfini çıkarın vb.


Teşekkürler. Görünüşe göre Notification.Name genişletilebilir ancak Notification.Key mümkün değildir. 'Key' is not a member type of 'Notification'. Buraya bakın: https://ibb.co/hDQYbd2
alpennec

Teşekkürler, görünüşe göre Keyyapı o zamandan beri kaldırılmış. Cevabı güncelliyorum
frouo

1

Swift 5.1 Özel Nesne / Tür

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




}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.