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
}
}
}
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
}
}
}