Home > Enterprise >  How can I open xib(ViewController) in xib(ViewController) when I tap Button without Navigation
How can I open xib(ViewController) in xib(ViewController) when I tap Button without Navigation

Time:01-11

I am not using storyboard.

I made customTabBarView. (I added 2 button on View).

I connected the buttons with the same function and gave the buttons a tag value.

How can I open the ViewController when I press the first button or press any button?

When I tap first Button I got this error.

Error:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x28184c020> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key countryListTableView.'
terminating with uncaught exception of type NSException

SceneDelegate:

guard let windowScene = (scene as? UIWindowScene) else { return }
let countryRouter = TabBarViewController()

let window = UIWindow(windowScene: windowScene)
window.rootViewController = countryRouter
self.window = window
window.makeKeyAndVisible()

ViewControllerCountryList:

class ViewControllerCountryList: UIViewController, CountryListModule.View { 
.
.
.
}

TabBarButton:

class TabBarViewController: UIViewController {

  @IBOutlet weak var contentView: UIView!
  @IBOutlet weak var tabBarView: UIView!
  
  override func viewDidLoad() {
        super.viewDidLoad()

        designableTabBarView()
    }
  
  private func designableTabBarView() {
    tabBarView.layer.cornerRadius = tabBarView.frame.size.height / 3
    tabBarView.clipsToBounds = true
  }
  @IBAction func onClickTabBarButton(_ sender: UIButton) {
    switch sender.tag {
    case 1:
      let nib = UINib(nibName: "ViewControllerCountryList", bundle: nil)
      guard let countryListVC = nib.instantiate(withOwner: nil, options: nil).first as? ViewControllerCountryList else { return }
      self.addChild(countryListVC)
      countryList.didMove(toParent: self)
    default:
      break
    }
  }
}

enter image description here

CodePudding user response:

The error is saying that you've loaded a NSObject and tried to use it as if it had a countryListTableView member. This suggests that the first item in your xib is not a ViewControllerCountryList.

If looking at the xib doesn't lead to an obvious solution, I suggest debugging by examining what is actually returned from loading the xib (rather than immediately trying to cast it).

CodePudding user response:

Using instantiate(withOwner:options:) is not really suitable for your task.

A better method is to use init(nibName:bundle:).

This extension wraps it into an easy one-line call:

extension UIViewController {
    static func loadFromNib() -> Self {
        func instantiateFromNib<T: UIViewController>() -> T {
            return T.init(nibName: String(describing: T.self), bundle: nil)
        }
        return instantiateFromNib()
    }
}

With that, you can now do:

let countryListVC = ViewControllerCountryList.loadFromNib()

For your "custom tab" layout, take a look at this:

class TabBarViewController: UIViewController {

    @IBOutlet weak var contentView: UIView!
    @IBOutlet weak var tabBarView: UIView!
    
    // keep references to the loaded view controllers
    var countryListVC: ViewControllerCountryList!
    var someOtherVC: SomeOtherViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        designableTabBarView()
    }
    
    private func designableTabBarView() {
        tabBarView.layer.cornerRadius = tabBarView.frame.size.height / 3
        tabBarView.clipsToBounds = true
    }
    
    @IBAction func onClickTabBarButton(_ sender: UIButton) {
        switch sender.tag {
        case 1:
            
            // remove other VC view from content view
            if someOtherVC != nil {
                someOtherVC.view.removeFromSuperview()
            }

            // if we haven't loaded ViewControllerCountryList yet
            if countryListVC == nil {
                countryListVC = ViewControllerCountryList.loadFromNib()
                self.addChild(countryListVC)
                contentView.addSubview(countryListVC.view)
                countryListVC.didMove(toParent: self)
            }

            // add ViewControllerCountryList view to contentView
            contentView.addSubview(countryListVC.view)
            countryListVC.view.frame = contentView.bounds
            countryListVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        case 2:
            
            // remove country list VC view from content view
            if countryListVC != nil {
                countryListVC.view.removeFromSuperview()
            }
            
            // if we haven't loaded SomeOtherViewController yet
            if someOtherVC == nil {
                someOtherVC = SomeOtherViewController.loadFromNib()
                self.addChild(someOtherVC)
                contentView.addSubview(someOtherVC.view)
                someOtherVC.didMove(toParent: self)
            }

            // add SomeOtherViewController view to contentView
            contentView.addSubview(someOtherVC.view)
            someOtherVC.view.frame = contentView.bounds
            someOtherVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        default:
            break
        }
    }

}
  •  Tags:  
  • Related