当我点击没有导航的按钮时,如何在 xib(ViewController) 中打开 xib(ViewController)

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

我没有使用故事板。

我制作了自定义TabBarView。 (我在视图上添加了 2 个按钮)。

我连接了具有相同功能的按钮,并给了按钮一个 tag 值。

如何在按下第一个按钮或任意按钮时打开ViewController?

当我点击第一个按钮时出现此错误。

错误:

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

场景代理:

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

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

ViewController国家/地区列表:

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

错误是说您加载了一个 NSObject 并试图像它有一个 countryListTableView 成员一样使用它。这表明您的 xib 中的第一项不是 ViewControllerCountryList.

如果查看 xib 没有找到明显的解决方案,我建议通过检查加载 xib 时实际返回的内容(而不是立即尝试转换它)来进行调试。

使用 instantiate(withOwner:options:) 不太适合您的任务。

更好的方法是使用init(nibName:bundle:)

此扩展将其包装成一个简单的单线调用:

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

有了它,您现在可以:

let countryListVC = ViewControllerCountryList.loadFromNib()

对于您的“自定义选项卡”布局,请看一下:

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

}