How do you add an observer in Swift to the default notification center? I'm trying to port this line of code that sends a notification when the battery level changes.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];
Swift 4.0 & Xcode 9.0+:
Send(Post) Notification:
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
OR
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])
Receive(Get) Notification:
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
Function-Method handler for received Notification:
@objc func methodOfReceivedNotification(notification: Notification) {}
Swift 3.0 & Xcode 8.0+:
Send(Post) Notification:
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
Receive(Get) Notification:
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
Method handler for received Notification:
func methodOfReceivedNotification(notification: Notification) {
// Take Action on Notification
}
Remove Notification:
deinit {
NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}
Swift 2.3 & Xcode 7:
Send(Post) Notification
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Receive(Get) Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)
Method handler for received Notification
func methodOfReceivedNotification(notification: NSNotification){
// Take Action on Notification
}
For historic Xcode versions...
Send(Post) Notification
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
Receive(Get) Notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)
Remove Notification
NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self) // Remove from all notifications being observed
Method handler for received Notification
func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
Annotate either the class or the target method with @objc
@objc private func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
// Or
dynamic private func methodOfReceivedNotification(notification: NSNotification) {
// Take Action on Notification
}
It's the same as the Objective-C API, but uses Swift's syntax.
Swift 4.2 & Swift 5:
NotificationCenter.default.addObserver(
self,
selector: #selector(self.batteryLevelChanged),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)
If your observer does not inherit from an Objective-C object, you must prefix your method with @objc
in order to use it as a selector.
@objc private func batteryLevelChanged(notification: NSNotification){
//do stuff using the userInfo property of the notification object
}
See NSNotificationCenter Class Reference, Interacting with Objective-C APIs
UIDeviceBatteryLevelDidChangeNotification
not in quotes? It's a string type.
@objc
.
A nice way of doing this is to use the addObserver(forName:object:queue:using:)
method rather than the addObserver(_:selector:name:object:)
method that is often used from Objective-C code. The advantage of the first variant is that you don't have to use the @objc
attribute on your method:
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)
and you can even just use a closure instead of a method if you want:
let observer = NotificationCenter.default.addObserver(
forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
object: nil, queue: nil) { _ in print("🔋") }
You can use the returned value to stop listening for the notification later:
NotificationCenter.default.removeObserver(observer)
There used to be another advantage in using this method, which was that it doesn't require you to use selector strings which couldn't be statically checked by the compiler and so were fragile to breaking if the method is renamed, but Swift 2.2 and later include #selector
expressions that fix that problem.
addObserver(_:selector:name:object:)
way of unregistering. You have to keep the object returned by addObserverForName(_:object:queue:usingBlock:)
and pass it to removeObserver:
addObserverForName(_:object:queue:usingBlock:)
.
UIViewController
and refer to self
in that closure, you need to use [weak self]
or you'll have a reference cycle and the memory leak.
Declare a notification name extension Notification.Name { static let purchaseDidFinish = Notification.Name("purchaseDidFinish") } You can add observer in two ways: Using 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"] } or using 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"] } Post your notification NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])
from iOS 9 and OS X 10.11. It is no longer necessary for an NSNotificationCenter observer to un-register itself when being deallocated. more info
For a block
based implementation you need to do a weak-strong dance if you want to use self
inside the block. more info
Block based observers need to be removed more info
let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self.localeChangeObserver)
Swift 3.0 in Xcode 8
Swift 3.0 has replaced many "stringly-typed" APIs with struct
"wrapper types", as is the case with NotificationCenter. Notifications are now identified by a struct Notfication.Name
rather than by String
. See the Migrating to Swift 3 guide.
Previous usage:
// 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)
New Swift 3.0 usage:
// 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)
All of the system notification types are now defined as static constants on Notification.Name
; i.e. .UIDeviceBatteryLevelDidChange
, .UIApplicationDidFinishLaunching
, .UITextFieldTextDidChange
, etc.
You can extend Notification.Name
with your own custom notifications in order to stay consistent with the system notifications:
// Definition:
extension Notification.Name {
static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}
// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)
Pass Data using NSNotificationCenter
You can also pass data using NotificationCentre in swift 3.0 and NSNotificationCenter in swift 2.0.
Swift 2.0 Version
Pass info using userInfo which is a optional Dictionary of type [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
}
}
Swift 3.0 Version
The userInfo now takes [AnyHashable:Any]? as an argument, which we provide as a dictionary literal in 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
}
}
Source pass data using NotificationCentre(swift 3.0) and NSNotificationCenter(swift 2.0)
In Swift 5
Let's say if want to Receive Data from ViewControllerB to ViewControllerA
ViewControllerA (Receiver)
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 (Sender)
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)
}
}
Swift 5 Notification Observer
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)
}
I'm able to do one of the following to successfully use a selector - without annotating anything with @objc:
NSNotificationCenter.defaultCenter().addObserver(self,
selector:"batteryLevelChanged:" as Selector,
name:"UIDeviceBatteryLevelDidChangeNotification",
object:nil)
OR
let notificationSelector: Selector = "batteryLevelChanged:"
NSNotificationCenter.defaultCenter().addObserver(self,
selector: notificationSelector,
name:"UIDeviceBatteryLevelDidChangeNotification",
object:nil)
My xcrun version shows Swift 1.2, and this works on Xcode 6.4 and Xcode 7 beta 2 (which I thought would be using Swift 2.0):
$xcrun swift --version
Apple Swift version 1.2 (swiftlang-602.0.53.1 clang-602.0.53)
@objc
if your observer class inherits from NSObject
.
String
to Selector
either. :)
@objc
annotation from the method in my non-NSObject
observer class, added the as Selector
casting to the String
selector name, and when the notification fires the app crashes. My Swift version is exactly the same as yours.
@objc
annotation works for you, and this way doesn't, then keep annotating!
In swift 2.2 - XCode 7.3, we use #selector
for NSNotificationCenter
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)
We should remove notification also.
Ex.
deinit
{
NotificationCenter.default.removeObserver(self, name:NSNotification.Name(rawValue: "notify"), object: nil)
}
This is very simple example of custom notification observer and post
Add Notification Observer
NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: Notification.Name("CustomeNotificationName"), object: nil)
Add Selector and handle Observer call
@objc func myFunction(notification: Notification) {
//Write you code
}
Post Notification(Observer) when it is required.
NotificationCenter.default.post(name: NSNotification.Name("CustomeNotificationName"), object: "Object", userInfo: ["key":"Value"])
Notes:- Make user when you leave screen you need to remove observer. e.g.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self);
}
In swift 3, Xcode 8.2:- checking battery state level
//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
}
NSNotificationCenter add observer syntax in Swift 4.0 for iOS 11
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
This is for keyboardWillShow notification name type. Other type can be selected from the available option
the Selector is of type @objc func which handle how the keyboard will show ( this is your user function )
#selector
must be annotated with @objc
. For example: @objc func keyboardShow() { ... }
That threw me for a minute in Swift 4!
Swift 5 & Xcode 10.2:
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryLevelDidChangeNotification),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)
Success story sharing
@objc
.methodOFReceivedNotication
must be either annotated withdynamic
or be a member of a subclass of NSObject.object 0x7fd68852d710 of class 'TestNotifications.MyObject' does not implement methodSignatureForSelector: -- trouble ahead
,Unrecognized selector -[TestNotifications.MyObject methodOFReceivedNotication:]