2

I've been looking at and trying all the solutions others have posted to this problem, but I'm still not getting it.

My use case is very simple. I have a viewController with a button, when that button is pressed I want to navigate to another tab and reload the data including an api call.

When using the button, I navigate to the tab fine, but viewDidAppear is not being called.

If on another tab, and navigate using the tab bar, viewDidAppear works fine. Also viewWillAppear is working, but I have to add a manual delay to the functions I want to call so it's not ideal.

So what do I need to do to navigate using self.tabBarController.selectedIndex = 0 and get the functionality of viewDidAppear?

Update: The viewWillAppear method I added gets called but I have to add a delay to my functions in order for them to work, and it's a bit clunky, not ideal. Not sure why viewDidAppear will not work :(

Here is a screenshot of the structure: enter image description here

I appreciate any help on this one!

The "current" ViewController is my tab index 2:

import UIKit

class PostPreviewVC: UIViewController {

//Here I create a post object and post it to the timeline with the below button

    @IBAction func postButtonPressed(_ sender: Any) {

    //create the post via Firebase api

    self.tabBarController?.selectedIndex = 0

    }
}

In my destination viewController:

import UIKit
import Firebase
import SDWebImage
import AVFoundation

class HomeVC: UIViewController {

// MARK: - PROPERTIES

var posts = [Post]()
let refreshControl = UIRefreshControl()
//more properties...


@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    setupUI()
    configureTableView()
    reloadTimeline()

    UserFirebase.timeline { (posts) in
        self.posts = posts
        self.tableView.reloadData()
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    print("viewDidAppear")

    _ = self.view
    setupUI()
    configureTableView()
    reloadTimeline()

    UserFirebase.timeline { (posts) in
        self.posts = posts
        self.tableView.reloadData()
    }
}

override func viewWillAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    print("viewWillAppear")

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        self.reloadTimeline()
        self.configureTableView()
    }
}

//All the tableview code below here...
}

Added a custom class for my tab bar controller:

import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    print("viewDidAppear in tabBar custom Class called")
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    print("viewWillAppear in tabBar custom Class called")
}
}
TJMac
  • 129
  • 1
  • 12
  • have you checked if tabBarController is nil or not?? – Jarvis The Avenger Jan 25 '19 at 05:04
  • @JarvisTheAvenger I just checked and it is not nil – TJMac Jan 25 '19 at 05:14
  • can you share more code on it or just structure of your navigation. – Jarvis The Avenger Jan 25 '19 at 05:15
  • try checking it in view will appear method of view controller life cycle. – Jarvis The Avenger Jan 25 '19 at 05:17
  • @JarvisTheAvenger good thinking, I added a viewWillAppear method and it does get called, but viewDidAppear does not... any idea why this would be? – TJMac Jan 25 '19 at 05:20
  • if you see view controller's lifecycle view will appear comes before view did appear. I feel there is something broken in navigation. sometime your animations and all don't work on view did appear. – Jarvis The Avenger Jan 25 '19 at 05:22
  • I just added a snapshot of the structure, each tab is it's own storyboard, does that affect things? – TJMac Jan 25 '19 at 05:23
  • In your tab bar controller, add this method viewDidAppear(_ animated: Bool) and call its superclass method and try checking then your view did appear work, – Jarvis The Avenger Jan 25 '19 at 05:25
  • @JarvisTheAvenger I'm a little embarrassed to ask, but where would I do that? Do I need to create a custom class for my tab bar controller? Or would I modify the UITabBarController.h file? I'm afraid to stray from swift and break everything lol – TJMac Jan 25 '19 at 05:36
  • you need to add a custom class for UITabbarController. Updated it as my answer. you can go with the viewWillAppear method to check viewcontroller is switched. – Jarvis The Avenger Jan 25 '19 at 05:39

2 Answers2

4

When you are using UITabBarController, the method viewDidLoad will called only once when any UIViewController is loaded in memory. After that, when you are navigating the same UIViewController, then it will load from memory.

In order to overcome this problem, you must divide your code in viewDidLoad & viewDidAppear. So, in viewDidLoad, you only put that code which you want to intialize once throughout the app such as adding UIView's or other things, while in viewDidAppear / viewWillAppear, you can make API calls or some functions which fetches dynamic data.

Finally, when you are calling self.tabBarController.selectedIndex = 0, it will call viewDidLoad only once and viewDidAppear / viewWillAppear every time when you are navigating that UIViewController.

Hope this helps to understand like how UITabBarController works.

Sohil R. Memon
  • 9,404
  • 1
  • 31
  • 57
  • This is great, thanks for taking the time. I had a typo in the question, I meant to ask how to get viewDidAppear to work... In the code I posted I have my viewDidAppear code, but it's not being called when I use self.tabBarController.selectedIndex = 0. Is there anything else I need to make that work? Some solutions talk about a subclass for UITabBarController, but I haven't had luck with those either. – TJMac Jan 25 '19 at 04:52
  • @TJMac Can you pls put some code like from where you are calling this? – Sohil R. Memon Jan 25 '19 at 04:53
  • Ok I just updated with more code to show context. My HomeVC has a lot of code so I simplified to keep it clean. let me know if there is more to consider than what I've added. Thanks again! – TJMac Jan 25 '19 at 05:11
2

For UITabBarController viewDidLoad only gets called once. and your viewWillAppear and viewDidAppear get called multiple times. you can either check if your viewWillAppear gets called or not. because your view will appear gets called before your viewDidAppear it's just like going through the reverse engineering process.

You can also add viewDidAppear method into your UITabBarController custom class. and call its superclass method into it in that way I think it will solve your problem.

Note: In the case of UITabbarController, Always do your UI update task and API calling a task in either viewWillAppear or viewDidAppear

Jarvis The Avenger
  • 2,750
  • 1
  • 19
  • 37
  • I just updated my post, I added custom class for my tab bar controller... viewWillAppear is being called, but I think it's too early so the code does not execute. I thought that would happen, that's why I wanted it in viewDidAppear. That method does not get called.. I'm stumped as to why – TJMac Jan 25 '19 at 06:26
  • it seems like it should b/c I'm able to print to the console, but the functions I'm calling are not being executed. I think it has to do with timing, so I'm debugging now to see where it breaks. But I still don't understand why viewDidAppear is not working. – TJMac Jan 26 '19 at 00:34
  • Update: So i added a slight delay to my viewWillAppear calls and they all work. It's not an ideal solution so I'm still going to work on finding out why viewDidAppear is not being called. – TJMac Jan 26 '19 at 01:24
  • I ended up removing my storyboard references and re-connecting them to get back the viewDidAppear method... not sure what broke or where, but your answer and comments helped a ton to debug. thanks again! – TJMac Jan 29 '19 at 20:34