viewWillDisapper isn't called when opening a second view with popOver - swift

On my mainVC I have a TableView with a button that should open the secondVC, where I can add things to show then in the Table, with the kind: "Present As Popover".
I'm opening the secondVC with performSegue(withIdentifier:"goToOtherView", sender: nil.
class FirstViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var groupData = ["Data, Data1, Data2"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
tableView.delegate = self
tableView.dataSource = self
}
#IBAction func btnTapped(_ sender: Any) {
performSegue(withIdentifier: "goToOtherView", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
print("FirstViewController will appear")
}
override func viewDidAppear(_ animated: Bool) {
print("FirstViewController did appear")
}
override func viewWillDisappear(_ animated: Bool) {
print("FirstViewController will disappear")
}
override func viewDidDisappear(_ animated: Bool) {
print("FirstViewController did disappear")
}
}
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
}
override func viewWillAppear(_ animated: Bool) {
print("SecoundViewController will appear")
}
override func viewDidAppear(_ animated: Bool) {
print("SecoundViewController did appear")
}
override func viewWillDisappear(_ animated: Bool) {
print("SecoundViewController will disappear")
}
override func viewDidDisappear(_ animated: Bool) {
print("SecoundViewController did disappear")
}
}
Storyboard
When I start the App
When I open the secondVC
And when I close the secondVC
The FirstViewController willDisappear and didDisappear are never being called, or even when the secondVC is closed the willAppear and didAppear. I want to call the function tableView.reloadData() when the FirstView willAppear/didAppear
It's kinda the same like the IOS default clock app, when you add a new alarm clock.

Quick guess, but I think that’s because of the presentation mode being pageSheet
Can you try to change it to fullScreen?
You can also change your segue configuration to be like:
View disappear won't be called since the view does not completely disappears from the window

Related

Swift How can I keep only the first page with a large title?

The large title of navigation item comes out when the app just describes execution. However, when I move to another page and come back, that mode is turned off. Create a viewDidLoad for each page as follows: What's the problem?
class CollectionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .always
}
next page
class AssetCollectionViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.largeTitleDisplayMode = .never
}
Possibly adding code didn't work.
override func viewDidDisappear(_ animated: Bool) {
self.navigationItem.largeTitleDisplayMode = .always
}
Change titleDisplay mode in viewWillppear function as it will always execute
class CollectionViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .always
}
How about doing all the implementation in your CollectionViewController like so:
override func viewWillDisappear(_ animated: Bool) {
navigationController?.navigationBar.prefersLargeTitles = false
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = true
}
When you're setting navigationItem.largeTitleDisplayMode in viewDidDisappear(_:), you're doing it for the current controller's navigationItem.
I suggest you to create UINavigationController subclass with:
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.prefersLargeTitles = true
}
Then set navigationItem.largeTitleDisplayMode to .never in controllers, where you don't want large title.

do something after first view controller appears

I have a View Controller with a button..
This button calls a "Present as Popover Seague" to a second view controller.
The second view controller has a close button with this function:
#IBAction func exit(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
Now I would like to do something in the first controller, after the second Controller is dismissed.
In the first view controller I tried this functions:
override func viewDidAppear(_ animated: Bool) {
print("viewDidAppear")
}
override func viewWillAppear(_ animated: Bool) {
print("viewWillAppear")
}
but no console log will shown.
Where is my mistake?
FirstViewContorller
import UIKit
class firstVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//ERROR
secondVC.dismissCompletion = {
print("dismissCompletion")
}
}
}
SecondVC (popover)
import UIKit
class secondVC: UIViewController {
var dismissCompletion: (() -> Void)?
// EXIT POPOVER
#IBAction func exit(_ sender: UIButton) {
self.dismiss(animated: true, completion: dismissCompletion)
}
}
The viewDidAppear() method of the main view controller won't be called because of the popover presentation style you use. If you choose to present the second view controller full screen - those methods will fire.
If we're sticking with the popover, the first thing you need to do is in your second view controller, the one that's being presented, add a property for a closure that will be executed upon its dismiss:
class PopoverViewController: UIViewContoller {
var dismissCompletion: (() -> Void)?
#IBAction func exit(_ sender: UIButton) {
self.dismiss(animated: true, completion: dismissCompletion)
}
}
And in your main view controller you define what needs to be done upon the popover's dismiss:
popoverViewContoller.dismissCompletion = {
// do stuff
}
UPDATE:
I assume you've setup the segue in your storyboard. I also assume that in your storyboard you've given the view controllers their respective class names:
This is what your code should look like:
class FirstViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let secondVC = segue.destination as? SecondViewController else {
return
}
secondVC.dismissCompletion = {
print("Popover dismissed")
}
}
}
class SecondViewController: UIViewController {
var dismissCompletion: (() -> Void)?
#IBAction func exit(_ sender: Any) {
dismiss(animated: true, completion: dismissCompletion)
}
}
Please note the classes naming and the way I got the secondVC instance.

How to transfer array variables between tab bar controllers?

I'm trying to understand the life cycle of view controllers. I need to use TabBar to switch controllers. And when switching controllers, I need the label to display life-cycle methods, not only of the controller on which I now find, but also from others.
I created an empty array private var arrayOfMethods = [String]() in which I add a triggered method every time.
class ViewController: UIViewController {
private var arrayOfMethods = [String]()
#IBOutlet var greenLabel: UILabel!
#IBOutlet var blueLabel: UILabel!
#IBOutlet var yellowLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
printMessage()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
printMessage()
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
printMessage()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
printMessage()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
printMessage()
}
func printMessage(line: Int = #line, function: String = #function) {
print("\(title ?? "nil"). Line: \(line) of function \(function)")
arrayOfMethods.append(function)
let string = arrayOfMethods.joined(separator: "\n")
greenLabel.text = "\(title ?? "nil") \(string)"
}
}
You can create a common class and call its function from all of your view controllers
class Helper: NSObject {
private var arrayOfMethods = [String]()
static let shared = Helper()
let mainLabel = UITextView(frame: CGRect(x: 100, y: 100, width: 300, height: 300))
private override init() {
super.init()
}
func printMessage(vc: UIViewController, line: Int = #line, function: String = #function) {
print("\(vc.title ?? "nil"). Line: \(line) of function \(function)")
arrayOfMethods.append( (vc.title ?? "nil") + "-" + function)
let string = arrayOfMethods.joined(separator: "\n")
guard let window = UIApplication.shared.keyWindow else { return }
if !window.subviews.contains(mainLabel) {
window.addSubview(mainLabel)
window.bringSubviewToFront(mainLabel)
}
mainLabel.text = string
}
}
And call this singleton class method from all your view controllers like this
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Helper.shared.printMessage(vc: self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Helper.shared.printMessage(vc: self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Helper.shared.printMessage(vc: self)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
Helper.shared.printMessage(vc: self)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
Helper.shared.printMessage(vc: self)
}
}
Output

How to hide and show label when navigation VC1 to VC2 back and forth

Say, I have a label show : Loading...
problem: When return from VC(2). The label is not hidden.
How to hide it when return from VC(2) and dont hide it when in navigating to VC(2) and show the message : Loading....
in VC(1)
#IBOutlet weak var lbLoadingMsg
In viewDidLoad() {
lbLoadingMsg.hidden = true
}
-2-- turn it on when prepare to navigate to VC(2)
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool
{
--code--
lbLoadingMsg.hidden = false
}
Override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
}
You can use NSNotificationCenter for that.
Follow this simple steps:
1.In your VC(2) add this code into your button from where you are going back:
#IBAction func goBack(sender: AnyObject) {
NSNotificationCenter.defaultCenter().postNotificationName("hide", object: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
2.In your First View add this code into viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "hideLabel:", name:"hide", object: nil)
}
now this method will call this function:
func hideLabel(notification: NSNotification){
self.lbLoadingMsg.hidden = true
}
And this will hide your label in first view when ever goBack button will pressed from first view.
Hope this will help you.
Write this in VC2
,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var identifier = segue.identifier
if(identifier! == "yourIdentifier"){
var vc1:VC1 = segue.destinationViewController as! VC1
vc1.lbLoadingMsg.hidden = true
}
}
func viewDidAppear(_ animated: Bool) {
lbLoadingMsg.hidden = true
}
Move
lbLoadingMsg.hidden = true
line from viewDidLoad to viewDidAppear. I think most quicker way.

Reset hidesBarsOnSwipe in swift

Where and how do I have to reset hidesBarsOnSwipe? I set the option in a View Controller which I push and want to reset it for the View Controller which did the push. What I tried until now is setting hidesBarsOnSwipe to false in the viewDidDisappear and in the viewDidLoad of the pushing ViewController.
The Navigationbar is still disappearing.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (!visiblePOIs.isEmpty) {
let beaconInfo = visiblePOIs[indexPath.item]
var controller = storyboard!.instantiateViewControllerWithIdentifier("DetailController")! as! DetailController
controller.setup(beaconInfo)
self.parentViewController!.navigationController?.pushViewController(controller, animated: true)
}
}
DetailController
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self
navigationController?.hidesBarsOnSwipe = true
self.automaticallyAdjustsScrollViewInsets = false
}
next view controller write in viewDidload
First Vc
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = true
}
Second VC
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
I hope its works
I had your exact problem. Here's how I solved it. (You can adapt this based on your needs.)
class MyViewController: UITableViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Correct the nav bar state unwinding from segues
self.navigationController?.hidesBarsOnSwipe = true
}
override func willMoveToParentViewController(parent: UIViewController?) {
super.willMoveToParentViewController(parent)
//Toggle the auto-hiding nav bar when this view gets added/removed from the nav controller
self.navigationController?.hidesBarsOnSwipe = !self.navigationController!.hidesBarsOnSwipe
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
//Reset the nav bar to visible when segueing to another view
self.navigationController?.navigationBarHidden = false
self.navigationController?.hidesBarsOnSwipe = false
}
}
This approach allows you to limit the functionality of the auto-hiding feature to the desired view controller without adding code to all associated view controllers.