Swift'te NSNotificationCenter addObserver


392

Swift'te varsayılan bildirim merkezine nasıl bir gözlemci eklersiniz? Pil seviyesi değiştiğinde bir bildirim gönderen kodun bu satırına bağlanmaya çalışıyorum.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];

Özellikle ne soruyorsun? Seçici nasıl çalışır?
nschum

1
"Seçici" türünün Swift'te sadece bir ip olduğunu fark etmedim. Belgelerde bundan bahsetmiyorum.
Berry Blue

Yanıtlar:


442

Objective-C API ile aynıdır, ancak Swift'in sözdizimini kullanır.

Hızlı 4.2 ve Hızlı 5:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.batteryLevelChanged),
    name: UIDevice.batteryLevelDidChangeNotification,
    object: nil)

Gözlemciniz bir Objective-C nesnesinden miras almazsa @objc, bir seçici olarak kullanmak için yöntemin önüne ön ek eklemeniz gerekir .

@objc private func batteryLevelChanged(notification: NSNotification){     
    //do stuff using the userInfo property of the notification object
}

Bkz NSNotificationCenter sınıfı başvurusu , Objective-C API'leri ile etkileşimde


3
Teşekkürler! Swift'te seçici ismini nasıl aktaracağımı bilmiyordum.
Berry Blue

14
@BerryBlue, yukarıdaki çözüm sizin için işe yaradı mı? Eğer işlev NSNotification parametre olarak kabul ederse "batteryLevelChanged" değiştirmek için "batteryLevelChanged:" inanıyorum.
Olshansk

1
@Olshansk Evet, haklısın. Buna ihtiyacın var. Teşekkürler!
Berry Blue

neden ki UIDeviceBatteryLevelDidChangeNotification tırnak içinde değil? Bu bir dize türüdür.
kmiklas

13
Sınıfı veya hedef yöntemi ile açıklama eklediğinizden emin olun @objc.
Klaas

757

Swift 4.0 ve Xcode 9.0+:

Gönder (Gönder) Bildirimi:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

VEYA

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])

Bildirim Alma (Alma):

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Alınan Bildirim için İşlev-Yöntem işleyicisi:

@objc func methodOfReceivedNotification(notification: Notification) {}

Swift 3.0 ve Xcode 8.0+:

Gönder (Gönder) Bildirimi:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

Bildirim Alma (Alma):

NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Alınan Bildirim için yöntem işleyici:

func methodOfReceivedNotification(notification: Notification) {
  // Take Action on Notification
}

Bildirimi Kaldır:

deinit {
  NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}

Swift 2.3 ve Xcode 7:

Bildirim Gönder

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

Bildirim Alma (Alma)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)

Alınan Bildirim için yöntem işleyici

func methodOfReceivedNotification(notification: NSNotification){
  // Take Action on Notification
}


Tarihi Xcode sürümleri için ...



Bildirim Gönder

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

Bildirim Alma (Alma)

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)

Bildirimi Kaldır

NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self) // Remove from all notifications being observed

Alınan Bildirim için yöntem işleyici

func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

@Objc ile sınıfa veya hedef yönteme açıklama ekleyin

@objc private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

// Or

dynamic private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

21
Sınıfı veya hedef yöntemi ile açıklama eklediğinizden emin olun @objc.
Klaas

1
@goofansu Emin misin? Saf bir Swift sınıfı olduğunda eklemeniz gerektiğini düşünüyorum.
Klaas

10
methodOFReceivedNoticationdynamicNSObject öğesinin alt sınıfına açıklamalı veya bir alt sınıfın üyesi olmalıdır.
Klaas

1
Değilse, bir çalışma zamanı uyarısı alıyorum object 0x7fd68852d710 of class 'TestNotifications.MyObject' does not implement methodSignatureForSelector: -- trouble ahead,Unrecognized selector -[TestNotifications.MyObject methodOFReceivedNotication:]
Klaas

2
@TaylorAllred, Cevabımı incelediğiniz için çok teşekkür ederim. Önerinizi gerçekten takdir ediyorum. Ben değiştirdim. Lütfen onu gözden geçir.
Yenile Dadhaniya

46

Bunu yapmanın güzel bir yolu, Objective-C kodunda sıkça kullanılan addObserver(forName:object:queue:using:)yöntem yerine yöntemi kullanmaktır addObserver(_:selector:name:object:). İlk varyantın avantajı, @objcözelliği yönteminizde kullanmak zorunda olmamanızdır :

    func batteryLevelChanged(notification: Notification) {
        // do something useful with this information
    }

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil,
        using: batteryLevelChanged)

ve isterseniz bir yöntem yerine bir kapatma bile kullanabilirsiniz:

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil) { _ in print("🔋") }

Bildirimi daha sonra dinlemeyi durdurmak için döndürülen değeri kullanabilirsiniz:

    NotificationCenter.default.removeObserver(observer)

Bu yöntemi kullanmanın başka bir avantajı vardı, bu da derleyici tarafından statik olarak kontrol edilemeyen seçici dizeleri kullanmanızı gerektirmiyordu ve bu yüzden yöntem yeniden adlandırılırsa kırılmaya kırılgandı, ancak Swift 2.2 ve sonra ekle #selector bu sorunu gideren ifadeler .


7
Bu harika! Bütünlük için kayıt dışı örneği de görmek istiyorum. addObserver(_:selector:name:object:) Kayıtsız kalmanın yolundan oldukça farklıdır . Nesneyi geri döndürmek addObserverForName(_:object:queue:usingBlock:)ve ona vermek removeObserver:
zorundasınız

1
Bunun, tarafından iade edilen itirazın kaldırılmasını da içerecek şekilde güncellenmesi gerekmektedir addObserverForName(_:object:queue:usingBlock:).
Abartma

3
Bu, connor veya Renish'inkinden çok daha iyi bir cevaptır (bu yorum sırasında her ikisi de yukarıda) çünkü Obj-C #selector yöntemlerini kullanmak zorunda kalıyor. Sonuç çok daha hızlı ve daha doğru, IMO. Teşekkürler!
patr1ck

2
Bunu, örneğin UIViewControllera'da kullanırsanız selfve bu kapanışa başvurursanız , kullanmanız gerektiğini [weak self]veya bir referans döngüsüne ve bellek sızıntısına sahip olacağınızı unutmayın.
Rob N

40

Xcode 8'de Swift 3.0

Swift 3.0, NotificationCenter'da olduğu gibi birçok "stringly-typeed" API'nin yerine struct"wrapper type" türlerini koydu . Bildirimler artık tarafından struct Notfication.Namedeğil, tarafından tanımlanmaktadır String. Bkz Swift 3 rehber göç .

Önceki kullanım:

// Define identifier
let notificationIdentifier: String = "NotificationIdentifier"

// Register to receive notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name: notificationIdentifier, object: nil)

// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationIdentifier, object: nil)

Yeni Swift 3.0 kullanımı:

// Define identifier
let notificationName = Notification.Name("NotificationIdentifier")

// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification), name: notificationName, object: nil)

// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)

Tüm sistem bildirim türleri artık statik sabitler olarak tanımlanmıştır Notification.Name; yani .UIDeviceBatteryLevelDidChange, .UIApplicationDidFinishLaunching, .UITextFieldTextDidChangevb

Notification.NameSistem bildirimleriyle tutarlı kalmak için kendi özel bildirimlerinizle genişletebilirsiniz :

// Definition:
extension Notification.Name {
    static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}

// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)

24
  1. Bir bildirim adı bildirin

    extension Notification.Name {
        static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
    }
  2. Gözlemciyi iki şekilde ekleyebilirsiniz:

    kullanma Selector

    NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: .purchaseDidFinish, object: nil)
    
    @objc func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }

    veya kullanarak block

    NotificationCenter.default.addObserver(forName: .purchaseDidFinish, object: nil, queue: nil) { [weak self] (notification) in
        guard let strongSelf = self else {
            return
        }
    
        strongSelf.myFunction(notification: notification)
    }
    
    func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }
  3. Bildiriminizi gönderin

    NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])

iOS 9 ve OS X 10.11'den. NSNotificationCenter gözlemcisinin, yeniden konumlandırılırken kayıttan çıkması artık gerekli değildir. Daha fazla bilgi

Bir İçin blocktabanlı uygulaması size kullanmak istiyorsanız zayıf-kuvvetli dansı yapmak gerekir selfbloğunun içinde. Daha fazla bilgi

Blok tabanlı gözlemcilerin daha fazla bilgi kaldırılması gerekir

let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self.localeChangeObserver)

5
"iOS 9 ve OS X 10.11'den. Artık bir NSNotificationCenter gözlemcisinin serbest bırakıldığında kayıttan çıkmasına gerek yok." Bu sadece Selector tabanlı gözlemciler için geçerlidir. Blok tabanlı gözlemcilerin hala kaldırılması gerekiyor.
Abhinav

8

NSNotificationCenter Kullanarak Veri Aktarma

Hızlı 3.0'da NotificationCentre ve hızlı 2.0'da NSNotificationCenter kullanarak da veri iletebilirsiniz.

Swift 2.0 Sürümü

[NSObject: AnyObject] türünde isteğe bağlı bir sözlük olan userInfo kullanarak bilgi iletilsin mi?

let imageDataDict:[String: UIImage] = ["image": image]

// Post a notification
 NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: imageDataDict)

// Register to receive notification in your class
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: notificationName, object: nil)

// handle notification
func showSpinningWheel(notification: NSNotification) {
  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

Swift 3.0 Sürümü

UserInfo artık [AnyHashable: Any] alıyor? Swift'te sözlük değişmezi olarak sunduğumuz bir argüman olarak

let imageDataDict:[String: UIImage] = ["image": image]

// post a notification
 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
// `default` is now a property, not a method call

// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

// handle notification
func showSpinningWheel(_ notification: NSNotification) {

  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

NotificationCentre (swift 3.0) ve NSNotificationCenter (swift 2.0) kullanarak kaynak geçiş verileri


Size yardımcı olduğunu duyduğuma sevindim :)
Sahil

6

In Swift 5

Diyelim ki ViewControllerB'den ViewControllerA'ya Veri Almak İstiyorsanız

ViewControllerA (Alıcı)

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Code for Passing Data through Notification Observer - - - - -
        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: - - - - - Method for receiving Data through Post Notificaiton - - - - -
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB (Gönderen)

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Set data for Passing Data Post Notification - - - - -
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }

}

2

Ben başarılı bir şekilde seçici kullanmak için aşağıdakilerden birini yapabiliyorum - olmadan @objc ile bir şey annotating:

NSNotificationCenter.defaultCenter().addObserver(self,
    selector:"batteryLevelChanged:" as Selector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

VEYA

let notificationSelector: Selector = "batteryLevelChanged:"

NSNotificationCenter.defaultCenter().addObserver(self,
    selector: notificationSelector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

Benim xcrun sürümü Swift 1.2 gösterir ve bu Xcode 6.4 ve Xcode 7 beta 2 (ki Swift 2.0 kullanmak olacağını düşündüm) üzerinde çalışır:

$xcrun swift --version

Apple Swift version 1.2 (swiftlang-602.0.53.1 clang-602.0.53)

@objcGözlemci sınıfınız miras alırsa açıklama eklemenize gerek yoktur NSObject.
Antonio Favata

Açıkça bir döküm için Ve gerekmez Stringiçin Selectorya. :)
Antonio Favata

@alfvata: Gözlemci sınıfım NSObject'ten miras almıyor. Swift tarzı AnyObject'ten miras alır. Dizeyi açıkça Seçiciye yayınlamak, diğer Objective-C ile ilgili geçici çözümlerden herhangi birini yapmaktan kaçınmamı sağlıyor.
leanne

Bunun nasıl çalıştığını anladığımdan emin değilim. Gözlemci @objcolmayan NSObjectsınıfımdaki yöntemden ek açıklama kaldırdım, seçici adına as Selectordöküm ekledim Stringve bildirim tetiklendiğinde uygulama çöktü. Swift sürümüm sizinkilerle tamamen aynı.
Antonio Favata

3
@alfavata, sana ne söyleyeceğimi bilmiyorum. Şimdi Xcode Beta 4'teyim ve hala çalışıyor. Projem tamamen Swift; Objective-C bileşeni yoktur. Belki de bu bir fark yaratır. Belki proje ayarlarında farklı bir şey var. Herhangi bir olasılık var! Şunu söyleyeceğim: @objcek açıklama sizin için çalıştığı sürece ve bu şekilde çalışmazsa, ek açıklama yapmaya devam edin!
leanne

2

Swift 2.2 olarak - XCode 7.3, kullandığımız #selectoriçinNSNotificationCenter

 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)

2

Bildirimi de kaldırmalıyız.

Ör.

deinit 
{
  NotificationCenter.default.removeObserver(self, name:NSNotification.Name(rawValue: "notify"), object: nil)

}

2
İOS 9'dan beri buna ihtiyacınız olmadığını düşünüyorum. Otomatik olarak yapılır.
Viktor Kucera

1

Hızlı 3'te, Xcode 8.2: - pil durumu seviyesini kontrol etme

//Add observer
NotificationCenter.default.addObserver(self, selector: #selector(batteryStateDidChange), name: NSNotification.Name.UIDeviceBatteryStateDidChange, object: nil)


 //Fired when battery level changes

 func batteryStateDidChange(notification: NSNotification){
        //perform manipulation here
    }

1

NSNotificationCenter , iOS 11 için Swift 4.0'da gözlemci sözdizimi ekliyor

  NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

Bu klavyeWillShow bildirim adı türü içindir. Mevcut tipten başka tip seçilebilir

Seçici, klavyenin nasıl görüneceğini işleyen @objc func türündedir (bu sizin kullanıcı işlevinizdir)


Sadece bu cevabı okuyan herkes için açıklığa kavuşturmak için: "Selector @objc func türündedir ..." ile ilişkili fonksiyonun #selectoraçıklanması gerekir @objc. Örneğin: @objc func keyboardShow() { ... }Swift 4'te beni bir dakika attı!
leanne

0

Swift 5 ve Xcode 10.2:

NotificationCenter.default.addObserver(
            self,
            selector: #selector(batteryLevelDidChangeNotification),
            name: UIDevice.batteryLevelDidChangeNotification,
            object: nil)

0

Swift 5 Bildirim Gözlemcisi

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelChanged), name: UIDevice.batteryLevelDidChangeNotification, object: nil)
}

@objc func batteryLevelChanged(notification : NSNotification){
    //do here code
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.batteryLevelDidChangeNotification, 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.