NSVotificationCenter在Swift中添加了addObserver

Ber*_*lue 382 nsnotificationcenter ios swift

如何在Swift中将观察者添加到默认通知中心?我正在尝试移植这行代码,以便在电池电量发生变化时发送通知.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

Ren*_*iya 737

Swift 4.0和Xcode 9.0+:

发送(发布)通知:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
Run Code Online (Sandbox Code Playgroud)

要么

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

接收(获取)通知:

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

接收通知的函数方法处理程序:

@objc func methodOfReceivedNotification(notification: Notification) {}
Run Code Online (Sandbox Code Playgroud)

Swift 3.0和Xcode 8.0+:

发送(发布)通知:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
Run Code Online (Sandbox Code Playgroud)

接收(获取)通知:

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

接收通知的方法处理程序:

func methodOfReceivedNotification(notification: Notification) {
  // Take Action on Notification
}
Run Code Online (Sandbox Code Playgroud)

删除通知:

deinit {
  NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}
Run Code Online (Sandbox Code Playgroud)

Swift 2.3和Xcode 7:

发送(发布)通知

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Run Code Online (Sandbox Code Playgroud)

接收(获取)通知

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)
Run Code Online (Sandbox Code Playgroud)

接收通知的方法处理程序

func methodOfReceivedNotification(notification: NSNotification){
  // Take Action on Notification
}
Run Code Online (Sandbox Code Playgroud)

对于历史悠久的Xcode版本......



发送(发布)通知

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Run Code Online (Sandbox Code Playgroud)

接收(获取)通知

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)
Run Code Online (Sandbox Code Playgroud)

删除通知

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

接收通知的方法处理程序

func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}
Run Code Online (Sandbox Code Playgroud)

使用@objc注释类或目标方法

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

// Or

dynamic private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}
Run Code Online (Sandbox Code Playgroud)

  • 一定要使用`@objc`注释类或目标方法. (20认同)
  • `methodOFReceivedNotication`必须用`dynamic`注释或者是NSObject的子类的成员. (10认同)
  • @TaylorAllred,非常感谢你回答我的回答.我真的很感激你的建议.我改变了它.请检讨一下. (2认同)

Con*_*nor 425

它与Objective-C API相同,但使用Swift的语法.

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: #selector(batteryLevelChanged:),
    name: UIDeviceBatteryLevelDidChangeNotification,
    object: nil)
Run Code Online (Sandbox Code Playgroud)

斯威夫特3:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.batteryLevelChanged:),
    name: .UIDeviceBatteryLevelDidChange,
    object: nil)
Run Code Online (Sandbox Code Playgroud)

Swift 4.2:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.batteryLevelChanged),
    name: UIDevice.batteryLevelDidChangeNotification,
    object: nil)
Run Code Online (Sandbox Code Playgroud)

如果您的观察者没有从Objective-C对象继承,则必须为方法添加前缀@objc,以便将其用作选择器.

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

请参阅NSNotificationCenter类参考,与Objective-C API交互

  • @BerryBlue,上述解决方案是否适合您?如果您的函数接受NSNotification作为参数,我相信您需要将"batteryLevelChanged"更改为"batteryLevelChanged:". (14认同)
  • 一定要使用`@objc`注释类或目标方法. (13认同)
  • 谢谢!我不知道如何在Swift中传递选择器名称. (3认同)

Jon*_*son 44

这样做的一个好方法是使用addObserver(forName:object:queue:using:)方法而不是addObserver(_:selector:name:object:)Objective-C代码中经常使用的方法.第一个变体的优点是您不必@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)
Run Code Online (Sandbox Code Playgroud)

如果你愿意,你甚至可以使用闭包而不是方法:

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

您可以使用返回的值稍后停止侦听通知:

    NotificationCenter.default.removeObserver(observer)
Run Code Online (Sandbox Code Playgroud)

使用这种方法曾经有另一个好处,那就是它不需要你使用编译器无法静态检查的选择器字符串,因此如果方法被重命名,则很容易破坏,但是Swift 2.2和以后包括解决该问题的#selector表达式.

  • 这很棒!为了完整起见,我还想看看未注册的例子.它与`addObserver(_:selector:name:object :)`取消注册的方式完全不同.你必须保持`addObserverForName(_:object:queue:usingBlock:)`返回的对象并将其传递给`removeObserver:` (7认同)
  • 这是一个比connor或Renish更好的答案(在评论时都是上面的),因为它不得不使用Obj-C#selector方法.结果更像是Swift-y,更正确,IMO.谢谢! (3认同)
  • 记住,如果你在一个`UIViewController`中使用它并在该闭包中引用`self`,你需要使用`[weak self]`或者你将有一个引用循环和内存泄漏. (2认同)

Jef*_*ton 41

Xcode 8中的Swift 3.0

struct与NotificationCenter一样,Swift 3.0已经用"包装类型" 取代了许多"串式"API .现在通过a struct Notfication.Name而不是by来识别通知String.请参阅迁移到Swift 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)
Run Code Online (Sandbox Code Playgroud)

新的Swift 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)
Run Code Online (Sandbox Code Playgroud)

所有系统通知类型现在都定义为静态常量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)
Run Code Online (Sandbox Code Playgroud)


War*_*shi 21

  1. 声明通知名称

    extension Notification.Name {
        static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以通过两种方式添加观察者:

    运用 Selector

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

    或使用 block

    NotificationCenter.default.addObserver(forName: .purchaseDidFinish, object: nil, queue: nil) { [weak self] (notification) in
        guard let strongSelf = self else {
            return
        }
    
        strongSelf.myFunction(notificaiont: notification)
    }
    
    func myFunction(notificaiont: Notification) {
        print(notificaiont.object ?? "") //myObject
        print(notificaiont.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 张贴你的通知

    NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])
    
    Run Code Online (Sandbox Code Playgroud)

来自iOS 9和OS X 10.11.NSNotificationCenter观察器不再需要在取消分配时取消注册.更多信息

对于block基础实现,如果你想self在块内使用,你需要做一个弱强舞.更多信息

  • _“从iOS 9和OS X 10.11开始。在取消分配时,NSNotificationCenter观察者不再需要注销自身。” _这仅适用于基于选择器的观察者。基于块的观察者仍然需要删除。 (4认同)

Sah*_*hil 8

使用NSNotificationCenter传递数据

您还可以使用swift 3.0中的NotificationCentre和swift 2.0中的NSNotificationCenter传递数据.

Swift 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   
  }
}
Run Code Online (Sandbox Code Playgroud)

Swift 3.0版本

userInfo现在需要[AnyHashable:Any]?作为一个参数,我们在Swift中作为字典文字提供

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   
  }
}
Run Code Online (Sandbox Code Playgroud)

传递数据使用NotificationCentre(swift 3.0)和NSNotificationCenter(swift 2.0)


swi*_*Boy 8

斯威夫特 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 ?? "")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)


Imr*_*eed 5

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

}
Run Code Online (Sandbox Code Playgroud)


小智 5

  1. 创建一个要在调用通知时执行的 objc 函数。
 @objc func reloadNotification(_ notification: Notification) {
        tblview.reloadData()
    }
Run Code Online (Sandbox Code Playgroud)
  1. 在视图中添加通知观察者已加载。
  NotificationCenter.default.addObserver(self, selector:#selector(reloadNotification(_:)), name: Notification.Name("reloadSideMenuDataNS"),object: nil) 
Run Code Online (Sandbox Code Playgroud)
  1. 将通知发布到您想要调用该函数的位置。
 NotificationCenter.default.post(name: Notification.Name("reloadSideMenuDataNS"), object: nil) 
Run Code Online (Sandbox Code Playgroud)
  1. 您可以通过以下方式删除视图中的通知确实消失了。
 NotificationCenter.default.removeObserver(self, name: Notification.Name("reloadSideMenuDataNS"), object: nil)
Run Code Online (Sandbox Code Playgroud)