The problem lies precisely in putting this code on all view controllers. All of them will receive notification when said event occurs (even if they are not the "present on screen" at the time of action).
A possible first solution is to put this code only in the first view controller (rootViewController
) of UINavigationController
, since it probably never goes out of memory (unless you replace the same).
Don’t forget to remove objects from NSNotificationCenter
, either in the deinit
or in the willMoveToParentViewController(nil)
, otherwise the object will be retained in memory.
One second solution is to use the methods applicationWillResignActive:
and applicationWillEnterForeground:
of Appdelegate, which were created precisely to deal with situations of this kind.
To implement this option, go to AppDelegate
and implements the logic within these two methods, being the applicationWillResignActive:
for when the app will enter the background and the applicationWillEnterForeground:
for when the app will return to foreground. The system calls these methods automagically (with the forgiveness of the joke) when the respective events happen.
You get access to your view controllers through the variable window
. The first view controller of the hierarchy is available in self.window.rootViewController
.
The problem with this solution is that you will have to go totally against the object-oriented design standards and you will have to force downcast, in order to access the methods of your view controllers, in that way:
let myVc = self.window!.rootViewController as! MyViewController
It will work, but the code will be attached, inelegant and will take a little work if you want to change the type of view controller. It’s your responsibility to decide whether this is bad for your application or not.
I saw that you are using a UINavigationController
, right?
One third solution (the best and most elegant, in my humble opinion) would be to create a subclass of UINavigationController
and overwrite the constructor.
In the new constructor, the only addition would be to register the object itself in the NSNotificationCenter
to receive the notifications you want to use. To give you an idea, it would be something like this:
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
NSNotificationCenter.defaultCenter.addObserver(self, selector: #selector(willEnterForeground), name: UIApplicationWillEnterForegroundNotification, object: nil)
}
// implementar willEnterForeground e afins
After you do that, just go on storyboard (if you are using it) and change the class of the UINavigationController
for your new class. If you are doing programmatically, just change the class that is instantiated.
Tip: I saw that, in your implementation, you simply "Pusha" (act of doing push) the mapViewControllerObject
in the pile of view controllers of navigation controller. This is very problematic, for one of these two reasons: If it is the same object, it will give error, because we are not allowed to put the same view controller more than once in the stack. If it is another object, will give you headache with Leak memory, if Apple accepts the app.
Each time the user leaves the application and comes back, a new hierarchy of controllers is added on top of the old, on the same stack. Want to test? It makes this method run multiple times and keeps looking at the memory consumption in the debug of the Xcode. It may sound silly, but trust me, it’s not. As your application becomes more complex, it will become a ram-eating monster (like google and firefox), especially for those users who keep switching from app to app all the time.
One solution: reset the entire stack by calling the method popToRootViewControllerAnimated:. If you implement the third solution, this would be a good implementation for the method that is called when the notification of application Did enter foreground.
How can I even use that second option you gave me?
– HideCode
I improved the answer.
– Lucas Barbosa