NotificationCenter issue on Swift 3 [duplicate] - ios

This question already has answers here:
NSNotificationCenter addObserver in Swift
(16 answers)
Closed 6 years ago.
I'm learning Swift 3 and I'm trying to using NSNotificationCenter. Here is my code:
func savePost(){
let postData = NSKeyedArchiver.archivedData(withRootObject: _loadedpost)
UserDefaults.standard().object(forKey: KEY_POST)
}
func loadPost(){
if let postData = UserDefaults.standard().object(forKey: KEY_POST) as? NSData{
if let postArray = NSKeyedUnarchiver.unarchiveObject(with: postData as Data) as? [Post]{
_loadedpost = postArray
}
}
//codeerror
NotificationCenter.default().post(NSNotification(name: "loadedPost" as NSNotification.Name, object: nil) as Notification)
}
and this is the observer:
override func viewDidLoad() {
super.viewDidLoad()
//codeerorr
NotificationCenter.default().addObserver(self, selector: Selector(("onPostLoaded")), name: "loadedPost", object: nil)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
It always gives me the error "signal SIGBRT". When I try to change the name in the observer, it's not an error, but obviously it didn't show anything. How do I fix this?

Swift 3 & 4
Swift 3, and now Swift 4, have 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. For more details see the now legacy Migrating to Swift 3 guide
Swift 2.2 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)
Swift 3 & 4 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)
// Stop listening notification
NotificationCenter.default.removeObserver(self, name: notificationName, object: nil)
All of the system notification types are now defined as static constants on Notification.Name; i.e. .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)
Swift 4.2 usage:
Same as Swift 4, except now system notifications names are part of UIApplication. So in order to stay consistent with the system notifications you can extend UIApplication with your own custom notifications instead of Notification.Name :
// Definition:
UIApplication {
public static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}
// Usage:
NotificationCenter.default.post(name: UIApplication.yourCustomNotificationName, object: nil)

Notifications appear to have changed again (October 2016).
// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(yourClass.yourMethod), name: NSNotification.Name(rawValue: "yourNotificatioName"), object: nil)
// Post notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "yourNotificationName"), object: nil)

For all struggling around with the #selector in Swift 3 or Swift 4, here a full code example:
// WE NEED A CLASS THAT SHOULD RECEIVE NOTIFICATIONS
class MyReceivingClass {
// ---------------------------------------------
// INIT -> GOOD PLACE FOR REGISTERING
// ---------------------------------------------
init() {
// WE REGISTER FOR SYSTEM NOTIFICATION (APP WILL RESIGN ACTIVE)
// Register without parameter
NotificationCenter.default.addObserver(self, selector: #selector(MyReceivingClass.handleNotification), name: .UIApplicationWillResignActive, object: nil)
// Register WITH parameter
NotificationCenter.default.addObserver(self, selector: #selector(MyReceivingClass.handle(withNotification:)), name: .UIApplicationWillResignActive, object: nil)
}
// ---------------------------------------------
// DE-INIT -> LAST OPTION FOR RE-REGISTERING
// ---------------------------------------------
deinit {
NotificationCenter.default.removeObserver(self)
}
// either "MyReceivingClass" must be a subclass of NSObject OR selector-methods MUST BE signed with '#objc'
// ---------------------------------------------
// HANDLE NOTIFICATION WITHOUT PARAMETER
// ---------------------------------------------
#objc func handleNotification() {
print("RECEIVED ANY NOTIFICATION")
}
// ---------------------------------------------
// HANDLE NOTIFICATION WITH PARAMETER
// ---------------------------------------------
#objc func handle(withNotification notification : NSNotification) {
print("RECEIVED SPECIFIC NOTIFICATION: \(notification)")
}
}
In this example we try to get POSTs from AppDelegate (so in AppDelegate implement this):
// ---------------------------------------------
// WHEN APP IS GOING TO BE INACTIVE
// ---------------------------------------------
func applicationWillResignActive(_ application: UIApplication) {
print("POSTING")
// Define identifiyer
let notificationName = Notification.Name.UIApplicationWillResignActive
// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)
}

I think it has changed again.
For posting this works in Xcode 8.2.
NotificationCenter.default.post(Notification(name:.UIApplicationWillResignActive)

Related

Notification Center Posting Notification with User-Info

For my code base, I have 3 functions and 3 dispatch groups (dg)
so when the 1st function is done, dg1's notify method is called and it calls func 2, and once that is done, dg2's notify method is called and func 3 is called once that is finished dg3's notify is called, I have my data and I use it for further processing.
All the above logic is in another file
I want to pass the data is of func 3, available in dg3's notify-execute method to my vc. I employed the notification center for this method. Using the following:
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
// For swift 4.0 and above put #objc attribute in front of function Definition
func showSpinningWheel(_ notification: NSNotification) {
if let image = notification.userInfo?["image"] as? UIImage {
// do something with your image
}
}
However I never get the notification. How do I resolve this problem. I want to pass the data from the dispatch group elsewhere -in this case my VC.

iOS: How to detect keyboard change event

Xcode 9.2, iOS 10.0+ , swift4.
I'm working on a project where user inputs english characters in UITextField and it converted to Japanese language characters. and it is working perfect. now, i want to allow user to input Japanese language characters direct from Japanese Keyboard.In this situation i want to know that the keyboard is changed from default to another type/language.
So, is there any function or Notification is available that can help me?
You can use the UITextInputCurrentInputModeDidChange notification to detect when the current keyboard language changes.
NotificationCenter.default.addObserver(self, selector: #selector(inputModeDidChange), name: .UITextInputCurrentInputModeDidChange, object: nil)
#objc func inputModeDidChange(_ notification: Notification) {
if let inputMode = notification.object as? UITextInputMode {
if let lang = inputMode.primaryLanguage {
// do something
}
}
}
In newer Swift versions the notification has been renamed to UITextInputMode.currentInputModeDidChangeNotification
Register to receive the following notification:
UITextInputCurrentInputModeDidChangeNotification
And anytime the keyboard language changes, you'll receive a notification. You can get more info from UITextInputMode docs.
With recent changes to iOS 12, swift 5.0 you can try:
func prepareForKeyboardChangeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(changeInputMode), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
}
#objc
func changeInputMode(notification: NSNotification) {
let inputMethod = txtInput.textInputMode?.primaryLanguage
//perform your logic here
}
in swift 4.2
//keyboard type change
NotificationCenter.default.addObserver(self, selector: #selector(inputModeDidChange), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
#objc func inputModeDidChange(_ notification: Notification) {
if let inputMode = notification.object as? UITextInputMode {
if let lang = inputMode.primaryLanguage {
print("langueage:: \(lang)")
}
}
}

Detect iOS app entering background

I'm working on a game for iOS coded in Swift. I've tried to find a way to detect when the app enters background mode or is interrupted for other reasons, for example a phone call but can't find anything. How do I do it?
You can add an observer to your view controller:
edit/update: Xcode 11 • Swift 5
iOS13 or later
UIScene.willDeactivateNotification
iOS12 or earlier
UIApplication.willResignActiveNotification
if #available(iOS 13.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIScene.willDeactivateNotification, object: nil)
} else {
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil)
}
and add a selector method to your view controller that will be executed when your app receives that notification:
#objc func willResignActive(_ notification: Notification) {
// code to execute
}
In swift 5.x: To observe app enters background event, add this code to your viewDidLoad() method.
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
#objc func appMovedToBackground() {
// do whatever event you want
}
you have to use UIApplication.didEnterBackgroundNotification.
If you want to observe if app came to foreground event, use UIApplication.willEnterForegroundNotification
So, the full code will be:
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(appCameToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
// Do any additional setup after loading the view.
}
#objc func appMovedToBackground() {
print("app enters background")
}
#objc func appCameToForeground() {
print("app enters foreground")
}
Swift3
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)
func appMovedToBackground() {
print("App moved to background!")
}
To detect the app enters background, you can check in the appDelegate.m
find the application delegate method
applicationDidEnterBackground
This method will get called, once the app enters background.
SwiftUI
From background
Text("Hello, World!")
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
print("To the foreground!")
}
To the background
Text("Hello, World!")
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
print("To the background!")
}
For SwiftUI you can use:
YourView()
.onReceive(NotificationCenter.default.publisher(for: UIScene.willDeactivateNotification)) { _ in
//...
}
Take a look at the delegate methods defined in your instance of UIApplicationDeletegate (called AppDelegate.m by default). Specifically the following would be useful:
- (void)applicationWillResignActive:(UIApplication *)application
This method is called to let your app know that it is about to move from the active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the app and it begins the transition to the background state. An app in the inactive state continues to run but does not dispatch incoming events to responders.
Taken from the Apple Documentation - here

NSNotificationCenter addObserver in Swift

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
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.
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)
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)
}
}
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)
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)
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);
}
Create an objc function which you want to execute when notification is called.
#objc func reloadNotification(_ notification: Notification) {
tblview.reloadData()
}
Add the notification observer in view did load.
NotificationCenter.default.addObserver(self, selector:#selector(reloadNotification(_:)), name: Notification.Name("reloadSideMenuDataNS"),object: nil)
post your notification where you want to call the function.
NotificationCenter.default.post(name: Notification.Name("reloadSideMenuDataNS"), object: nil)
you can remove your notification in view did disappear with below.
NotificationCenter.default.removeObserver(self, name: Notification.Name("reloadSideMenuDataNS"), object: nil)
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)
}
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 )
Swift 5 & Xcode 10.2:
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryLevelDidChangeNotification),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)

Handling applicationDidBecomeActive - "How can a view controller respond to the app becoming Active?"

I have the UIApplicationDelegate protocol in my main AppDelegate.m class, with the applicationDidBecomeActive method defined.
I want to call a method when the application returns from the background, but the method is in another view controller. How can I check which view controller is currently showing in the applicationDidBecomeActive method and then make a call to a method within that controller?
Any class in your application can become an "observer" for different notifications in the application. When you create (or load) your view controller, you'll want to register it as an observer for the UIApplicationDidBecomeActiveNotification and specify which method that you want to call when that notification gets sent to your application.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(someMethod:)
name:UIApplicationDidBecomeActiveNotification object:nil];
Don't forget to clean up after yourself! Remember to remove yourself as the observer when your view is going away:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationDidBecomeActiveNotification
object:nil];
More information about the Notification Center.
Swift 3, 4 Equivalent:
adding observer
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidBecomeActive),
name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
object: nil)
removing observer
NotificationCenter.default.removeObserver(self,
name: .UIApplicationDidBecomeActive, // UIApplication.didBecomeActiveNotification for swift 4.2+
object: nil)
callback
#objc func applicationDidBecomeActive() {
// handle event
}
Swift 2 Equivalent:
let notificationCenter = NSNotificationCenter.defaultCenter()
// Add observer:
notificationCenter.addObserver(self,
selector:Selector("applicationWillResignActiveNotification"),
name:UIApplicationWillResignActiveNotification,
object:nil)
// Remove observer:
notificationCenter.removeObserver(self,
name:UIApplicationWillResignActiveNotification,
object:nil)
// Remove all observer for all notifications:
notificationCenter.removeObserver(self)
// Callback:
func applicationWillResignActiveNotification() {
// Handle application will resign notification event.
}
Swift 5
fileprivate func addObservers() {
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidBecomeActive),
name: UIApplication.didBecomeActiveNotification,
object: nil)
}
fileprivate func removeObservers() {
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
}
#objc fileprivate func applicationDidBecomeActive() {
// here do your work
}
Swift 4.2
Add observer-
NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: UIApplication.didBecomeActiveNotification, object: nil)
Remove observer-
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
Handle Event-
#objc func handleEvent() {
}
With Swift 4, Apple advises via a new compiler warning that we avoid the use of #selector in this scenario. The following is a much safer way to accomplish this:
First, create a variable that will hold the observer instance (that will be used to cancel it):
var didBecomeActiveObserver: NSObjectProtocol
Then create a lazy var that can be used by the notification:
lazy var didBecomeActive: (Notification) -> Void = { [weak self] _ in
// Do stuff
}
If you require the actual notification be included, just replace the _ with notification.
Next, we set up the notification to observe for the app becoming active.
func setupObserver() {
didBecomeActiveObserver = NotificationCenter.default.addObserver(
forName: UIApplication.didBecomeActiveNotification,
object: nil,
queue:.main,
using: didBecomeActive)
}
The big change here is that instead of calling a #selector, we now call the var created above. This can eliminate situations where you get invalid selector crashes.
Finally, we remove the observer.
func removeObserver() {
NotificationCenter.default.removeObserver(didBecomeActiveObserver)
}
Swift 5 version:
NotificationCenter.default.addObserver(self,
selector: #selector(loadData),
name: UIApplication.didBecomeActiveNotification,
object: nil)
Removing the observer is no longer required in iOS 9 and later.
In Swift 5
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
}
#objc private func applicationWillResignActive() {
}
#objc private func applicationDidBecomeActive() {
}
The Combine way:
import Combine
var cancellables = Set<AnyCancellable>()
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
.sink { notification in
// do stuff
}.store(in: &cancellables)
If any of you is using SwiftUI:
.onReceive(NotificationCenter.default.publisher(
for: UIApplication.didBecomeActiveNotification)) { _ in
print("DID BECOME ACTIVE")
}
)
Cleaner Swift 5+ solution
Add the observer to init or viewDidLoad:
NotificationCenter.default.addObserver(self,
selector: #selector(appDidBecomeActive),
name: UIApplication.didBecomeActiveNotification,
object: nil)
You don't need to remove the observer as other answers suggest. It will be done automatically.
#objc private func appDidBecomeActive() {
// do your magic
}
For Swift5 MacOS, you need to use NSApplication instead of UIApplication.
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidBecomeActive),
name: (NSApplication.didBecomeActiveNotification),
object: nil)
}

Resources