स्विफ्ट में NSNotificationCenter addObserver


392

आप डिफ़ॉल्ट अधिसूचना केंद्र में स्विफ्ट में एक पर्यवेक्षक कैसे जोड़ सकते हैं? मैं कोड की इस पंक्ति को पोर्ट करने की कोशिश कर रहा हूं जो बैटरी स्तर में बदलाव होने पर एक अधिसूचना भेजता है।

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

आप विशेष रूप से क्या पूछ रहे हैं? चयनकर्ता कैसे काम करता है?
nschum

1
मुझे महसूस नहीं हुआ कि "चयनकर्ता" प्रकार स्विफ्ट में एक स्ट्रिंग है। डॉक्स में इसका कोई उल्लेख नहीं है।
बेरी ब्लू

जवाबों:


442

यह Objective-C API के समान है, लेकिन स्विफ्ट के सिंटैक्स का उपयोग करता है।

स्विफ्ट 4.2 और स्विफ्ट 5:

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

यदि आपका ऑब्जर्वर ऑब्जेक्टिव-सी ऑब्जेक्ट से इनहेरिट नहीं करता है, तो आपको @objcचयनकर्ता के रूप में इसका उपयोग करने के लिए अपनी विधि को उपसर्ग करना होगा ।

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

उद्देश्य-सी एपीआई के साथ बातचीत करते हुए , NSNotificationCenter वर्ग संदर्भ देखें


3
धन्यवाद! मुझे नहीं पता था कि स्विफ्ट में चयनकर्ता नाम कैसे पारित किया जाए।
बेरी ब्लू

14
@ जीरीब्लू, क्या आपके लिए उपरोक्त समाधान काम करता है? मेरा मानना ​​है कि आपको "BatteryLevelChanged" को "BatteryLevelChanged:" में बदलने की आवश्यकता है: यदि आपका फ़ंक्शन NSNotification को एक पैरामीटर के रूप में स्वीकार करता है।
ओलशनस्क

1
@Olshansk हाँ, आप सही हैं। आप की जरूरत है कि धन्यवाद!
बेरी ब्लू

UIDeviceBatteryLevelDidChangeNotificationउद्धरणों में क्यों नहीं है? यह एक स्ट्रिंग प्रकार है।
किमीकिल्स

13
कक्षा या लक्ष्य पद्धति के साथ एनोटेट अवश्य करें @objc
क्लेआस

757

स्विफ्ट 4.0 और Xcode 9.0+:

भेजें (पोस्ट) अधिसूचना:

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

या

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

प्राप्त करें (प्राप्त करें) सूचना:

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

सूचना प्राप्त करने के लिए कार्य-विधि हैंडलर:

@objc func methodOfReceivedNotification(notification: Notification) {}

स्विफ्ट 3.0 और Xcode 8.0+:

भेजें (पोस्ट) अधिसूचना:

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

प्राप्त करें (प्राप्त करें) सूचना:

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

प्राप्त अधिसूचना के लिए विधि हैंडलर:

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

अधिसूचना निकालें:

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

स्विफ्ट 2.3 और Xcode 7:

भेजें (पोस्ट) अधिसूचना

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

प्राप्त (प्राप्त) अधिसूचना

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

अधिसूचना प्राप्त करने के लिए विधि हैंडलर

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


ऐतिहासिक Xcode संस्करणों के लिए ...



भेजें (पोस्ट) अधिसूचना

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

प्राप्त (प्राप्त) अधिसूचना

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

अधिसूचना निकालें

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

अधिसूचना प्राप्त करने के लिए विधि हैंडलर

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

@Objc के साथ या तो कक्षा या लक्ष्य विधि का उल्लेख करें

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

// Or

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

21
कक्षा या लक्ष्य पद्धति के साथ एनोटेट अवश्य करें @objc
कालस

1
@goofansu क्या आप सुनिश्चित हैं? मुझे लगता है कि आपको इसे जोड़ना होगा जब यह एक शुद्ध स्विफ्ट वर्ग होगा।
क्लेस

10
methodOFReceivedNoticationया तो एनोटेट होना चाहिए या dynamicNSObject के एक उपवर्ग का सदस्य होना चाहिए।
क्लेस

1
यदि नहीं, तो मुझे एक रनटाइम चेतावनी मिलती है object 0x7fd68852d710 of class 'TestNotifications.MyObject' does not implement methodSignatureForSelector: -- trouble ahead,Unrecognized selector -[TestNotifications.MyObject methodOFReceivedNotication:]
क्लेस

2
@TaylorAllred, मेरे जवाब की समीक्षा करने के लिए बहुत बहुत धन्यवाद। मैं वास्तव में आपके सुझाव की सराहना कर रहा हूं। मैंने इसे बदल दिया है। कृपया इसकी समीक्षा करें।
रेनिश दढानिया

46

ऐसा करने का एक अच्छा तरीका उस addObserver(forName:object:queue:using:)विधि के बजाय विधि का उपयोग करना addObserver(_:selector:name:object:)है जो अक्सर उद्देश्य-सी कोड से उपयोग किया जाता है। पहले संस्करण का लाभ यह है कि आपको @objcअपने तरीके पर विशेषता का उपयोग नहीं करना है :

    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)

और यदि आप चाहें तो आप एक विधि के बजाय एक बंद का उपयोग भी कर सकते हैं:

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

आप बाद में अधिसूचना के लिए सुनना बंद करने के लिए दिए गए मान का उपयोग कर सकते हैं:

    NotificationCenter.default.removeObserver(observer)

इस पद्धति का उपयोग करने में एक और फायदा हुआ करता था, वह यह था कि आपको चयनकर्ता स्ट्रिंग्स का उपयोग करने की आवश्यकता नहीं है जो संकलक द्वारा सांख्यिकीय रूप से जांच नहीं की जा सकती है और इसलिए विधि का नाम बदलने पर तोड़ने के लिए नाजुक थे, लेकिन स्विफ्ट 2.2 और बाद में शामिल हैं #selector उस समस्या को ठीक करने वाले भाव


7
यह भी खूब रही! पूर्णता के लिए मैं सिर्फ अपंजीकृत उदाहरण भी देखना चाहूंगा। यह काफी अलग है तो addObserver(_:selector:name:object:) अपंजीकृत होने का तरीका। आपको वस्तु को लौटा कर addObserverForName(_:object:queue:usingBlock:)उसे पास रखना होगाremoveObserver:
लुकास गूसेन

1
इसके द्वारा लौटाए गए ऑब्जेक्ट के डी-पंजीकरण को शामिल करने के लिए अपडेट करने की आवश्यकता है addObserverForName(_:object:queue:usingBlock:)
हाइपरबोले

3
यह कॉनर की या रेनिश की (इस टिप्पणी के समय दोनों ऊपर) की तुलना में बहुत बेहतर उत्तर है क्योंकि यह ओब्ज-सी # चयनकर्ता विधियों का उपयोग करने के लिए मिलता है। परिणाम बहुत अधिक है स्विफ्ट-वाई और अधिक सही, आईएमओ। धन्यवाद!
पेट्रॉक 1

2
याद रखें, यदि आप इसका उपयोग करते हैं, कहते हैं, एक UIViewControllerऔर selfउस बंद में देखें , तो आपको उपयोग करने की आवश्यकता है [weak self]या आपके पास एक संदर्भ चक्र और मेमोरी लीक होगा।
रोब एन

40

Xcode 8 में स्विफ्ट 3.0

स्विफ्ट 3.0 ने struct"रैपर टाइप" के साथ कई "कड़ाई से टाइप किए गए" एपीआई को बदल दिया है , जैसा कि अधिसूचना अधिसूचना के साथ होता है। अब नोटिफिकेशन की struct Notfication.Nameबजाय इसके द्वारा पहचाना जाता है String। देखें स्विफ्ट 3 गाइड की ओर पलायन

पिछला उपयोग:

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

नई स्विफ्ट 3.0 उपयोग:

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

सिस्टम अधिसूचना प्रकारों के सभी अब स्थैतिक स्थिरांक के रूप में परिभाषित किए गए हैं Notification.Name; यानी .UIDeviceBatteryLevelDidChange, .UIApplicationDidFinishLaunching, .UITextFieldTextDidChange, आदि

Notification.Nameसिस्टम सूचनाओं के अनुरूप बने रहने के लिए आप अपनी स्वयं की कस्टम सूचनाओं का विस्तार कर सकते हैं :

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

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

24
  1. एक अधिसूचना नाम घोषित करें

    extension Notification.Name {
        static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
    }
  2. आप पर्यवेक्षक को दो तरीकों से जोड़ सकते हैं:

    का उपयोग करते हुए 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"]
    }

    या उपयोग कर रहा है 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. अपनी अधिसूचना पोस्ट करें

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

iOS 9 और OS X 10.11 से। अब NSNotificationCenter पर्यवेक्षक के लिए यह आवश्यक नहीं है कि वह निपटाए जाने के दौरान स्वयं को पंजीकृत करे। और जानकारी

blockयदि आप selfब्लॉक के अंदर उपयोग करना चाहते हैं, तो एक आधारित कार्यान्वयन के लिए आपको एक कमजोर-मजबूत नृत्य करने की आवश्यकता है। और जानकारी

ब्लॉक आधारित पर्यवेक्षकों को अधिक जानकारी निकालने की आवश्यकता है

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

5
"iOS 9 और OS X 10.11 से। अब NSNotificationCenter पर्यवेक्षक के लिए यह आवश्यक नहीं है कि वह निपटाए जाने पर स्वयं को पंजीकृत करें।" यह केवल चयनकर्ता आधारित पर्यवेक्षकों के लिए सच है। ब्लॉक आधारित पर्यवेक्षकों को अभी भी हटाने की आवश्यकता है।
अभिनव

8

NSNotificationCenter का उपयोग करके डेटा पास करें

आप स्विफ्ट 3.0 में नोटिफीकेशन और स्विफ्ट 2.0 में NSNotificationCenter का उपयोग करके डेटा भी पास कर सकते हैं।

स्विफ्ट 2.0 संस्करण

UserInfo का उपयोग करके पास की जानकारी जो कि एक वैकल्पिक शब्दकोश का प्रकार है [NSObject: AnyObject]?

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

स्विफ्ट 3.0 संस्करण

UserInfo अब [AnyHashable: Any] लेता है? एक तर्क के रूप में, जिसे हम स्विफ्ट में एक शब्दकोश शाब्दिक के रूप में प्रदान करते हैं

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

नोटिफिकेशन वेबकैम (स्विफ्ट 3.0) और NSNotificationCenter (स्विफ्ट 2.0) का उपयोग करके स्रोत पास डेटा


यह सुनकर खुशी हुई कि आपने :)
साहिल

6

में स्विफ्ट 5

मान लीजिए कि अगर ViewControllerB से ViewControllerA से डेटा प्राप्त करना चाहते हैं

ViewControllerA (रिसीवर)

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 (प्रेषक)

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

मैं चयनकर्ता का सफलतापूर्वक उपयोग करने में निम्न में से एक करने में सक्षम हूं - @objc के साथ कुछ भी एनोटेट किए बिना :

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

या

let notificationSelector: Selector = "batteryLevelChanged:"

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

मेरा xcrun संस्करण स्विफ्ट 1.2 दिखाता है, और यह Xcode 6.4 और Xcode 7 बीटा 2 (जो मुझे लगा कि स्विफ्ट 2.0 का उपयोग होगा) पर काम करता है:

$xcrun swift --version

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

@objcयदि आपके पर्यवेक्षक वर्ग को विरासत में मिला है, तो आपको इसके साथ एनोटेट करने की आवश्यकता नहीं है NSObject
एंटोनियो फवाटा

और आपको स्पष्ट रूप Stringसे Selectorया तो एक कास्ट करने की आवश्यकता नहीं होनी चाहिए । :)
एंटोनियो फवटा

@alfvata: मेरा पर्यवेक्षक वर्ग NSObject से विरासत में नहीं मिला है। यह AnyObject, स्विफ्ट-शैली से विरासत में मिला है। स्पष्ट रूप से चयनकर्ता को स्ट्रिंग का चयन करने से मुझे किसी अन्य उद्देश्य-सी-संबंधित वर्कअराउंड को करने से बचने की अनुमति मिलती है।
लीनन

मुझे यकीन नहीं है कि मैं समझता हूं कि यह कैसे काम करता है। मैंने @objcअपने गैर- NSObjectपर्यवेक्षक वर्ग में विधि से एनोटेशन को हटा दिया , चयनकर्ता के नाम में as Selectorकास्टिंग जोड़ा String, और जब अधिसूचना ऐप को क्रैश कर देती है। मेरा स्विफ्ट संस्करण बिल्कुल आपके जैसा है।
एंटोनियो फवाटा

3
@alfavata, मुझे नहीं पता कि आपको क्या बताना है। मैं अब Xcode Beta 4 पर हूं, और यह अभी भी काम कर रहा है। मेरा प्रोजेक्ट पूरी तरह से स्विफ्ट है; कोई उद्देश्य-सी घटक नहीं हैं। शायद इससे फर्क पड़ता है। हो सकता है कि प्रोजेक्ट सेटिंग्स में कुछ अलग हो। संभावनाओं की कोई संख्या है! मैं कहता हूँ: जब तक @objcएनोटेशन आपके लिए काम करता है, और इस तरह से नहीं करता है, तब तक एनोटेटिंग करते रहें!
झुकना

2

स्विफ्ट 2.2 - एक्सकोड 7.3 में, हम इसके लिए उपयोग #selectorकरते हैंNSNotificationCenter

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

2

हमें अधिसूचना भी निकाल देनी चाहिए।

पूर्व।

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

}

2
मेरा मानना ​​है कि iOS 9 के बाद से आपको इसकी आवश्यकता नहीं है। यह स्वचालित रूप से किया जाता है।
विक्टर कुचेरा

1

स्विफ्ट 3 में, Xcode 8.2: - बैटरी स्टेट लेवल की जाँच

//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 के लिए स्विफ्ट 4.0 में पर्यवेक्षक सिंटैक्स जोड़ें

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

यह KeyboardWillShow अधिसूचना नाम प्रकार के लिए है। उपलब्ध विकल्प से अन्य प्रकार का चयन किया जा सकता है

चयनकर्ता @objc func प्रकार का है, जो यह बताता है कि कीबोर्ड कैसे दिखाएगा (यह आपका उपयोगकर्ता कार्य है)


इस उत्तर को पढ़ने वाले किसी को भी स्पष्ट करने के लिए: "चयनकर्ता @objc func ... प्रकार का है" का अर्थ है कि इससे जुड़े फ़ंक्शन #selectorको एनोटेट किया जाना चाहिए @objc। उदाहरण के लिए: @objc func keyboardShow() { ... }कि मुझे स्विफ्ट 4 में एक मिनट के लिए फेंक दिया!
लीनन

0

स्विफ्ट 5 और Xcode 10.2:

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

0

स्विफ्ट 5 अधिसूचना पर्यवेक्षक

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)

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.