为何presentViewController会重复调用viewDidLoad?myTableView为nil报错求助
首先明确一点:你遇到的问题既不是Storyboard控制器无法present纯代码控制器,也不是Xcode的bug——这是一个典型的配置错误导致的问题。
核心原因
你的项目中存在一个未通过正确方式加载的ViewController实例:这个实例没有从Storyboard加载对应的界面布局,导致myTableView这个IBOutlet没有被绑定(值为nil),当它的viewDidLoad方法被调用时,就会触发nil错误。
而这个错误实例的出现,大概率是因为你在Storyboard中犯了一个低级错误:把UITableViewCell的自定义类设置成了ViewController,而不是正确的UITableViewCell子类(或者默认的UITableViewCell)。
当tableView需要复用cell时,会根据你在Storyboard中设置的类创建实例——如果类是ViewController,那创建出来的就是一个ViewController对象,但这个对象并没有加载它自己的Storyboard界面,自然没有myTableView的IBOutlet连接。当这个错误的ViewController的view被访问(比如tableView要显示这个“cell”),就会调用它的viewDidLoad,此时执行myTableView.dataSource = self就会崩溃。你误以为是点击cell执行present时触发的,可能是因为点击动作刚好触发了cell的复用逻辑,导致这个错误实例被创建。
解决方案
按照以下步骤排查修复:
修正UITableViewCell的类配置
- 打开你的Storyboard,选中tableView中的cell。
- 打开右侧面板的
Identity Inspector(第三个图标,显示身份证样式的那个)。 - 检查
Class字段:确保它是UITableViewCell(或者你自定义的cell子类),而不是ViewController。如果不小心设成了ViewController,改回来即可。
验证ViewController的IBOutlet连接
- 选中Storyboard中的
ViewController界面,打开右侧面板的Connections Inspector(最后一个图标,显示箭头样式的那个)。 - 找到
myTableView的IBOutlet,确认它已经正确连接到了tableView上——没有红色感叹号,连接指向正确的tableView控件。
- 选中Storyboard中的
避免手动初始化未绑定界面的ViewController
- 确保你在项目的其他地方(比如AppDelegate/SceneDelegate、其他控制器中)没有直接通过
ViewController()这种方式初始化实例。如果需要获取ViewController的实例,应该从Storyboard加载:
(注意要先给Storyboard中的let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerID") as! ViewControllerViewController设置正确的Storyboard ID)
- 确保你在项目的其他地方(比如AppDelegate/SceneDelegate、其他控制器中)没有直接通过
补充说明
从Storyboard创建的控制器完全可以present纯代码编写的控制器,这是iOS开发中非常常规的操作,不存在任何技术限制。你的问题和这个操作本身无关,完全是配置错误导致的。
内容的提问来源于stack exchange,提问作者neo

