swiftnavbarviewcontrollertabbar

How to Organize my ViewScreens on Swift Programmatic UI


I'm learning Programmatic UI and am a little bit obsessed with clean code.

I'm currently building a TabBarVC so that I can manage all of my VC's but I get an error message while doing this.

import UIKit

class MainTabBarVC: UITabBarController {
  
  let firstVC         = FirstVC()
  let secondVC        = SecondVC()
  
  let firstNavVC      = UINavigationController(rootViewController: firstVC)  // Cannot use instance member 'firstVC' within property initializer; property initializers run before 'self' is available
  let secondNavVC     = UINavigationController(rootViewController: secondVC) // Cannot use instance member 'secondVC' within property initializer; property initializers run before 'self' is available
  
  let viewControllers = [firstNavVC, secondNavVC]
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    self.setupViews()
  }
  
  func setupViews() {
    // Nav Configs
    self.firstVC.view.backgroundColor     = .systemBackground
    self.firstVC.navigationItem.title     = "First Nav"
    
    self.secondVC.view.backgroundColor    = .systemBackground
    self.secondVC.navigationItem.title    = "Second Nav"
    
    // Tab Configs
    self.firstNavVC.tabBarItem.title      = "First TAB"
    
    self.secondNavVC.tabBarItem.title     = "Second TAB"
  }
}

I know if I put firtNavVC, secondNavVC, and viewcontrollers inside the setupViews it is gonna work but I don't like it when one function has too many lines of codes especially when it gets bigger.

So except for my question, are there any extension or enum functions that I can easily manage all of my UINavigationController, UITabBarController, and UIViewController such as enumeration that can call the function whenever I need to call or add a new VC.


Solution

  • You could change your lets into lazy vars.

    class MainTabBarVC: UITabBarController {
      
      lazy var firstVC         = FirstVC()
      lazy var secondVC        = SecondVC()
      
      lazy var firstNavVC      = UINavigationController(rootViewController: firstVC)
      lazy var secondNavVC     = UINavigationController(rootViewController: secondVC)
      
      lazy var viewControllers = [firstNavVC, secondNavVC]
      
      override func viewDidLoad() {
        super.viewDidLoad()
        
        self.setupViews()
      }
    

    However, I think your impulse to maintain instance property references to all these view controllers is mistaken. What I would do is just move the lets into setupViews. You don't need a permanent reference to any of these objects; you just need to create them, configure them, and assign the view controllers as children of your tab bar controller (your code is missing that crucial step, by the way).