Search code examples
iosswiftuitabbarcontroller

Call a function from complex UITabbarcontroller that all view controllers use


I have a problem that is taking me time to solve... It is about the way my UITabBarController class interacts with the rest of the view controllers it owns.

This is what I have thought for my application. I don't know if it is the most convenient, that's why I ask for help.

First. In my Scene delegate i have:

guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)
        window?.makeKeyAndVisible()
        window?.rootViewController = TabBar()

*TabBar is my Custom Class of UITabBarController.

My goal is to have a User type that updates in all view controllers when a function that requires it is called.

I've tried addchild and protocols from TabBar() but I haven't been able to set it correctly.

basic scheme

  1. Scene Delegate
  2. TabBar
  • Receives user information from the database and saves it in a User type variable.
  • I define the viewcontrollers[HomeController, ProfileCont....] and pass User type
  1. When I am in the Profile controller (for example), and the user clicks on a button, I want the User variable of my TabBar to be updated, and also to be updated in the Home Controller, ProfileController.... (all of them)

Sorry for so much text, but I wanted to explain it in the best possible way.

I attach some code.

Thanks for the help!

    class TabBar: UITabBarController {
        
        private var user: User?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .white
            UITabBar.appearance().backgroundColor = .white
            UITabBar.appearance().unselectedItemTintColor = .lightGray
            tabBar.tintColor = .black
    
            fetchUserData()
            
        }
        
        func fetchUserData() {
            print("hey")
            guard let currentUid = Auth.auth().currentUser?.uid else { return }
            Service.shared.fetchUserData(uid: currentUid) { user in
                self.user = user
                self.setupVCs()
            }
        }
    
        func setupVCs() {
            
            guard let user = self.user else { return }
            
            viewControllers = [
                
                createNavController(for: HomeController(user: user), title: NSLocalizedString("Pedidos", comment: ""), image: UIImage(named: "pedidos")!),
                createNavController(for: SignUpController(), title: NSLocalizedString("Mapa", comment: ""), image: UIImage(named: "location")!),
                createNavController(for: InformePeriodos(user: user), title: NSLocalizedString("Ganancias", comment: ""), image: UIImage(named: "euro")!),
                createNavController(for: RetirarEfectivo(user: user), title: NSLocalizedString("Agenda", comment: ""), image: UIImage(named: "calendar")!),
                createNavController(for: PerfilController(user: user), title: NSLocalizedString("Perfil", comment: ""), image: UIImage(named: "person")!)
                
            ]
            
        }
      
       
        fileprivate func createNavController(for rootViewController: UIViewController,title: String,image: UIImage) -> UIViewController {
            let navController = UINavigationController(rootViewController: rootViewController)
            navController.tabBarItem.title = title
            navController.tabBarItem.image = image
            return navController
            
        }
    
       
    }

Here my Profile controller button action

    @objc func confirmar(){
                
           //efectivo, and gP and retiro are some data
           DriverService.shared.updateRetiro(efectivo: saldoEfectivo, gP: gananciasPagadas, retiro: doubleinputValue) {
                
                guard let currentUid = Auth.auth().currentUser?.uid else { return }
                Service.shared.fetchUserData(uid: currentUid) { user in
                    self.user = user
                    self.configureUI()
                    //i need to call FETCHUSERDATA FROM MY TABBAR HERE?
                    self.removeSpinner()
                }
                
           }
                          
     }

i think that call fetchuserdata in my profileController can resolve part of the problem


Solution

  • I post the solution if helps everyone with same issue

        import UIKit
        import Firebase
        import CoreLocation
    
        class TabBar: UITabBarController {
            
            private var user: User?
            
            override func viewDidLoad() {
                super.viewDidLoad()
                self.overrideUserInterfaceStyle = .light
               
                fetchUserData()
                
                let nc = NotificationCenter.default
                nc.addObserver(self, selector: #selector(updateUser), name: NSNotification.Name(rawValue: "updateUser"), object: nil)
    
            }
            
            
            @objc func updateUser() {
                
                print("updateUser")
                guard let currentUid = Auth.auth().currentUser?.uid else { return }
                Service.shared.fetchUserData(uid: currentUid) { user in
                    self.user = user
                    self.setupVCs()
                }
                
            }
           
            
            // MARK: - Helper Functions
          
            func fetchUserData() {
                print("hey")
                guard let currentUid = Auth.auth().currentUser?.uid else { return }
                Service.shared.fetchUserData(uid: currentUid) { user in
                    self.user = user
                    self.setupVCs()
                }
            }
    
            func setupVCs() {
                
                guard let user = self.user else { return }
                
                viewControllers = [
                    
                    createNavController(for: HomeController(user: user), title: NSLocalizedString("Pedidos", comment: ""), image: UIImage(named: "pedidos")!),
                    createNavController(for: RiderMap(user: user), title: NSLocalizedString("Mapa", comment: ""), image: UIImage(named: "location")!),
                    createNavController(for: InformePeriodos(user: user), title: NSLocalizedString("Ganancias", comment: ""), image: UIImage(named: "euro")!),
                    createNavController(for: CalendarController(user: user), title: NSLocalizedString("Agenda", comment: ""), image: UIImage(named: "calendar")!),
                    createNavController(for: PerfilController(user: user), title: NSLocalizedString("Perfil", comment: ""), image: UIImage(named: "person")!)
                    
                ]
                
            }
            
            override var preferredStatusBarStyle: UIStatusBarStyle {
                .lightContent
            }
            override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
                return .slide
            }
            
           
            fileprivate func createNavController(for rootViewController: UIViewController,
                                                              title: String,
                                                              image: UIImage) -> UIViewController {
                
               
                let navController = UINavigationController(rootViewController: rootViewController)
                navController.tabBarItem.title = title
                navController.tabBarItem.image = image
                return navController
                
            }
          
    
        }
    

    And then... the function that send notification to this tabbar from other view controller (without delegates)

    @objc func updateUser(){
           
           NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateUser"), object: nil)     
               
     }