通过初始化器向视图传值时遇nil解包崩溃问题排查
我正在开发一款消息应用,在显示用户间消息线程的ChatView界面中,希望让用户能够查看聊天对象的个人资料。用户从用户列表选择聊天对象后,通过segue跳转至ChatView并完成用户初始化。在ChatView中,我将显示聊天对象名称的导航标题设为按钮,点击后跳转至个人资料页,代码如下:
// line inside another function setting up the navigation title let button = UIButton(type: .custom) button.frame = CGRect(x: 0, y: 0, width: 100, height: 30) button.titleLabel?.textColor = .white button.setTitle(self.otherUser.name, for: .normal) button.addTarget(self, action: #selector(showUserProfile), for: .touchUpInside) navigationItem.titleView = button @objc func showUserProfile() { let viewUserProfile = ViewProfileViewController() viewUserProfile.user = self.otherUser navigationController?.pushViewController(viewUserProfile, animated: true) }
测试时,在个人资料页出现错误:(11db) Unexpectedly found nil while implicitly unwrapping an Optional value,导致应用崩溃,请问问题出在哪里?
可能的原因及解决方法
个人资料页的user属性是隐式解包可选类型,未正确初始化就被使用
如果ViewProfileViewController里user定义成var user: User!这种隐式解包类型,页面加载时(比如viewDidLoad)直接调用该属性,一旦user未赋值或赋值失败,就会触发崩溃。
解决办法:- 把
user改成非隐式解包的可选类型var user: User?,使用前做可选绑定:if let user = user { // 在这里处理用户信息,比如设置昵称、头像 } - 确保给
viewUserProfile赋值user后,再执行页面中依赖user的逻辑。
- 把
ChatView里的otherUser本身为nil
虽然你说通过segue完成了ChatView的初始化,但可能self.otherUser并未正确传递数据,本身就是nil,导致传给个人资料页的也是nil,而对方又直接隐式解包这个值。
解决办法:- 检查ChatView的初始化逻辑,比如在跳转的
prepare(for:sender:)里确认用户数据是否正确传递:override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let chatVC = segue.destination as? ChatView { // 确保selectedUser不是nil chatVC.otherUser = selectedUser } } - 在
showUserProfile方法里先判断otherUser是否存在,再跳转:@objc func showUserProfile() { guard let targetUser = self.otherUser else { return } let viewUserProfile = ViewProfileViewController() viewUserProfile.user = targetUser navigationController?.pushViewController(viewUserProfile, animated: true) }
- 检查ChatView的初始化逻辑,比如在跳转的
个人资料页在Storyboard中创建,但你用了代码直接初始化
如果ViewProfileViewController是通过Storyboard拖拽创建的,直接用ViewProfileViewController()初始化会导致页面上的IBOutlet(比如昵称标签、头像ImageView)未关联,这些IBOutlet如果是隐式解包的,就会触发nil崩溃。
解决办法:
从Storyboard里实例化页面:@objc func showUserProfile() { guard let targetUser = self.otherUser else { return } // 替换成你的Storyboard名称 let storyboard = UIStoryboard(name: "Main", bundle: nil) // 替换成你在Storyboard里给页面设置的ID if let viewUserProfile = storyboard.instantiateViewController(withIdentifier: "ViewProfileVC") as? ViewProfileViewController { viewUserProfile.user = targetUser navigationController?.pushViewController(viewUserProfile, animated: true) } }记得要在Storyboard里给
ViewProfileViewController设置正确的Storyboard ID。
内容的提问来源于stack exchange,提问作者Vandal

