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.
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)
In swift 2.2 - XCode 7.3, we use #selector
for NSNotificationCenter
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)
Swift 5 & Xcode 10.2:
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryLevelDidChangeNotification),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)
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)
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) {}
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)
}
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
}
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("