View will appear is not firing when we dismiss notification settings overlay - ios

I have a view controller when a button clicked I'm taking the user to app settings.
UIApplication.openApplicationSettings()
When I come back from appsettings to app then viewwillappear method is not firing.
or is there any other method that will let us know the appsettings is dismissed and user is seeing the screen right now.

You should be using app lifecycle events (SceneDelegate/AppDelegate), not view controller lifecycle events (viewDidLoad, viewDidAppear, etc). sceneDidBecomeActive(_:) should be fine for your purposes — for iOS 13+, you should be using SceneDelegate to listen to scene phases, like going to settings (becoming inactive) and then coming back (becoming active again).
/// SceneDelegate.swift
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
/// your code here
}
If you want to listen to sceneDidBecomeActive directly in your view controller, try listening to the didActivateNotification notification.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver( /// add observer
self,
selector: #selector(activated),
name: UIScene.didActivateNotification,
object: nil
)
}
#objc func activated() {
print("View controller is back now")
}
}

Subscribe to following appdelegate events
applicationDidBecomeActive
or
applicationWillEnterForeground
In ViewDidLoad use below code snippet
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
and use below method
#objc func applicationDidBecomeActive(notification: NSNotification) {
updateTableUI()
}
Remove observer
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

Related

iOS viewWillAppear not being called when returning from background, even with UIModalPresentationStyle.FullScreen, in iOS 13+

Why isn't iOS calling viewWillAppear when our application is returning from the background, even when I've set UIModalPresentationStyle.FullScreen?
viewWillAppear is a function that responds to a view controller's state change. Background and foreground states are different; they are done at an app level.
You can still respond app state changes by using notifications:
override func viewDidAppear(_ animated: Bool) {
// ...
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveForegroundNotification), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func didReceiveForegroundNotification() {
// app returned from the background
}
Your view controller will listen to events until it is deallocated or removed as an observer. If you don't want to execute code when the view controller has dissappeared, you can do it on viewDidDisappear:
override func viewDidDisappear(_ animated: Bool) {
// ..
NotificationCenter.default.removeObserver(self)
}

UITabBar Lifecycle's methods are not fired from background start

I've have a UITabBar controller as main controller, with 2 tabs. Each tab is a NavigatorViewController with a UIViewController embedded.
If I open the application from background after a previous cold launch, none of the ViewWillAppear (UITabBarController, UIViewController) is fired.
How can I call the lifecycle of UITabBarChildren when user come from backgroud? (IE: From a notification)
That is not in the life cycle because the state of controllers is not changing during background mode or other application events.
You should observe for applicationWillEnterForegroundNotification
class VC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Listen for application event somewhere early like `ViewDidLoad`
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForegroundNotification), name: UIApplication.willEnterForegroundNotification, object: nil)
}
// Implement a function that you want to execute when event happen
#objc func applicationWillEnterForegroundNotification() {
// Do anything before application Enter Foreground
}
// Remove observer when the controller is going to remove to prevent further issues
deinit {
NotificationCenter.default.removeObserver(self)
}
}
When application comes from background non viewWillAppear/viewDidAppear is called for any active vc , you need to listen to app delegate like applicationWillEnterForegroundNotification
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForegroundNotification), name: UIApplication.willEnterForegroundNotification, object: nil)
#objc func applicationWillEnterForegroundNotification(_ notification: NSNotification) {
print("To-Do")
}
You can add an observer to UIApplicationWillEnterForeground in your controllers.
Posted shortly before an app leaves the background state on its way to
becoming the active app.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,selector: #selector(self.appEnteredFromBackground(_:)),name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}
#objc func appEnteredFromBackground(_ notification: NSNotification) {
print("From background")
}

Which View Controller is active when app comes to foreground?

Normally I can find out when a View Controller appears with
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
This won't be called though if the user presses the home button or for some other reason the app goes to the background and then returns to the foreground. To find out when the app comes to the foreground I can add an observer to the Notification Center.
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("FirstViewController")
}
#objc func appWillEnterForeground() {
print("app in foreground")
}
}
However, my problem is that I have a tabbed app I want to know which View Controller is active when the app comes back into the foreground. The Notification center just sends a general message. Even though I an setting the notification observer in the first tab, it could be on any tab when the app goes into the background.
NSNotification.Name.UIApplicationWillEnterForeground
is a notification thrown by Notification Center. So obviously that is not related to any specific VC. What you can do rather is,
#objc func appWillEnterForeground() {
if self.viewIfLoaded?.window != nil {
// viewController is visible
}
}
Though notification of App entering foreground gets triggered to every viewController observing it, only the VC which is currently loaded and visible will have its code in if condition executed. That gives you a control to decide which VC is currently visible.
EDIT 1:
All that you want to figure out is the top ViewController in navigation stack of TabBarControllerwhen app comes to foreGround, you can add the observer for NSNotification.Name.UIApplicationWillEnterForeground only in UITabBarControllerand in
#objc func appWillEnterForeground() {
var vc : UIViewController = tabBarController.viewControllers![tabBarController.selectedIndex]
while vc.presentedViewController != nil || self.childViewControllers.count != 0 {
if vc.presentedViewController != nil {
vc = vc.presentedViewController!
}
else {
vc = vc.childViewControllers.last!
}
}
print("\(vc) should be the top most vc")
}
Use the Notification Observer and your appWillEnterForeground() or any event which gets fired from the observer in all view controllers under tab controller. So whichever the view controller you came back to will get your notification event get triggered in that particular VC. If you're looking for a centralized solution, this scattered gun approach may not work.

Swift - notification observer is called several times

I have viewController and inside in viewDidLoad I have
NSNotificationCenter.defaultCenter().addObserver(self, selector: "showNextQuestions", name: "showNextQuestionsID", object: nil)
In another controller I have
NSNotificationCenter.defaultCenter().postNotificationName("showNextQuestionsID", object: nil)
If I go home from app and launch it again function showNextQuestionID fires two times.
I tried to use
func applicationDidEnterBackground(application: UIApplication) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: "showNextQuestionsID", object: nil)
}
But this doesn't help,
and in viewController
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
How can I fix this ?
You are not removing your notification observer in the right place. You register the observer in your view controller subclass, and you need to remove it in the same class. A logical place is to override the viewWillDisappear method. Place the following code in your view controller subclass:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
Also remove
NSNotificationCenter.defaultCenter().removeObserver(self, name: "showNextQuestionsID", object: nil)
From your AppDelegate. When you supply the 'self' argument in the AppDelegate, it is referring to the AppDelegate class, not your view controller. When you call to remove your notification observer in the view controller sublcass, self is your view controller, which is what you want.
Last, when you call simply removeObserver(self) with no other arguments, it will unregister all the observers for that object. That way you don't have to go through and list each observer by name.
Put your observers in AppDelegate or a singleton, so that you can easily add and remove an observer during application states.
applicationDidEnterBackground and deinit should be ok.
The problem is the way you are trying to remove the observer in applicationDidEnterBackground. You are trying to remove the observer from AppDelegate and you need to remove the observer from your ViewController.
To fix the problem:
1) Listen for UIApplicationDidEnterBackgroundNotification in your view controller:
func init() {
super.init()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "myAppDidEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
}
2) Implement the method that listen to UIApplicationDidEnterBackgroundNotification
func myAppDidEnterBackground() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: "showNextQuestionsID", object: nil)
}
3) Extra. You could also listen for UIApplicationWillEnterForegroundNotification in order to add again your custom notification

How to detect the closing of the NofiticationCenter in Swift / Xcode?

I have a UITableView and I want to to reload, when the NotificationCenter has been dismissed over the running app.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"dismissedNC", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
func dismissedNC() {
println("NC has been dismissed") // doesn't get printed
self.tableView.reloadData()
}
Any ideas why it doesn't work?
While the notification center was present, the app was never in the background, so it does not come to the foreground when the notification center is dismissed - and so there is no UIApplicationWillEnterForegroundNotification. The app is activated, not foregrounded. Watch for UIApplicationDidBecomeActiveNotification instead.

Resources