Xcode Storyboard绑定ViewController类后界面不显示问题咨询
问题根因
你当前通过abaViewController()直接调用构造方法初始化子控制器的写法,只会生成纯代码的控制器实例,完全不会加载Storyboard中为该控制器配置的界面、输出口连线,所以你在Storyboard里搭建的UI、嵌入的YouTube播放器根本不会被加载,自然无法正常显示。
修复步骤
1. 为Storyboard中的子控制器配置Storyboard ID
- 打开Storyboard,选中类设置为
abaViewController的控制器页面 - 打开右侧身份检查器(卡片样式图标),在Identity分组下找到Storyboard ID输入框,填入唯一标识(比如直接填
abaViewController),勾选下方的Use Storyboard ID选项 - 对
abbViewController、abcViewController、abdViewController三个子控制器重复上述操作,每个控制器的Storyboard ID保持唯一即可
额外提醒:Swift官方命名规范要求类名首字母大写,你当前abaViewController这类小写开头的类名很容易和变量、方法名混淆,后续项目复杂度提升后排查问题会很麻烦,建议调整为AbaViewController这类大写开头的命名。
2. 替换子控制器的初始化逻辑
原来直接初始化的写法不会走Storyboard加载流程,需要改成从Storyboard实例化控制器,替换你类中原来四个子控制器的属性定义代码:
// 先获取对应Storyboard实例,如果你的子控制器在Main.storyboard里就用下面这行,在其他Storyboard就替换对应的文件名 private let targetStoryboard = UIStoryboard(name: "Main", bundle: .main) // 把原来的let属性改成lazy懒加载,第一次使用时才从Storyboard加载实例 private lazy var abaController: abaViewController = { guard let vc = targetStoryboard.instantiateViewController(withIdentifier: "abaViewController") as? abaViewController else { fatalError("请检查abaViewController的Storyboard ID、类名配置是否正确") } return vc }() private lazy var abbController: abbViewController = { guard let vc = targetStoryboard.instantiateViewController(withIdentifier: "abbViewController") as? abbViewController else { fatalError("请检查abbViewController的Storyboard ID、类名配置是否正确") } return vc }() private lazy var abcController: abcViewController = { guard let vc = targetStoryboard.instantiateViewController(withIdentifier: "abcViewController") as? abcViewController else { fatalError("请检查abcViewController的Storyboard ID、类名配置是否正确") } return vc }() private lazy var abdController: abdViewController = { guard let vc = targetStoryboard.instantiateViewController(withIdentifier: "abdViewController") as? abdViewController else { fatalError("请检查abdViewController的Storyboard ID、类名配置是否正确") } return vc }()
用
lazy修饰属性是为了延迟控制器初始化时机,避免App启动时一次性加载四个带视频的控制器造成内存峰值过高;fatalError会在你Storyboard配置错误时直接抛出明确的崩溃信息,不用无头绪排查加载失败问题。
3. 可选优化(降低内存占用)
你当前的AddChildControllers()方法会在viewDidLoad阶段一次性把四个子控制器全部添加到父视图,四个页面的YouTube播放器会同时初始化,内存占用很高。可以改成按需加载的逻辑,第一次切换到对应菜单时再添加子控制器:
- 先删除
viewDidLoad里对AddChildControllers()的调用,给类增加一个属性记录当前显示的子控制器:
private var currentShowingVC: UIViewController?
- 修改菜单选中的代理方法逻辑,替换原来的显示隐藏逻辑:
func didSelectMenuItem2(named: SideMenuItem2) { sideMenu?.dismiss(animated: true, completion: nil) title = named.rawValue let targetVC: UIViewController switch named { case .aba: targetVC = abaController case .abb: targetVC = abbController case .abc: targetVC = abcController case .abd: targetVC = abdController } // 点击的就是当前显示的页面,不需要操作 guard currentShowingVC != targetVC else { return } // 目标控制器还没添加过的话,再走添加子控制器流程 if targetVC.parent == nil { addChild(targetVC) targetVC.view.frame = view.bounds view.addSubview(targetVC.view) targetVC.didMove(toParent: self) } // 隐藏旧控制器,显示新控制器 currentShowingVC?.view.isHidden = true targetVC.view.isHidden = false currentShowingVC = targetVC }
- 在
viewDidLoad的最后,加一行代码默认加载第一个菜单页面:
didSelectMenuItem2(named: .aba)
原来的AddChildControllers()方法可以直接删掉。
常见问题排查
如果修改完还是无法正常显示,按顺序检查以下配置:
- Storyboard中对应控制器的Custom Class类名拼写完全正确,Module字段选中当前App的target,不要留空
- 代码中传入的Storyboard ID和Storyboard里配置的完全一致,注意大小写敏感
- 子控制器中YouTube播放器的Auto Layout约束设置正确,没有出现视图尺寸为0的情况;不要在
viewDidLoad里设置播放器frame,最好在viewDidLayoutSubviews回调里更新播放器尺寸,避免布局未完成时拿到错误的宽高 - 子控制器的视图没有被其他自定义视图遮挡,视图层级顺序正确
内容的提问来源于stack exchange,提问作者AIRONE
相关产品推荐
相关产品推荐

