Swift通过segue传值后解包Optional值偶现Found nil错误怎么解决?
问题根本原因
你遇到的报错核心是异步回调执行时序晚于视图生命周期调用时机:
DatabaseConnect.fetchTransactionUser是异步网络请求,回调闭包的执行时机晚于segue跳转完成、第二个视图控制器加载完成的时机- 你的
fetchFeed()大概率是在viewDidLoad/viewWillAppear这类视图生命周期方法里调用,此时异步回调还没返回,userId还没被赋值,仍然是初始的nil值,强制解包(!)就会触发崩溃 - 而点击事件是用户跳转页面后过一段时间才触发,此时异步回调已经执行完成,
userId已经被赋值,所以不会报错
排查步骤
- 在第二个控制器的
viewDidLoad、fetchFeed()、userId的didSet方法里分别加打印,确认各方法的执行顺序,验证是否是异步时序问题:
// 第二个控制器里修改userId的定义 var userId: String? { didSet { print("userId被赋值:\(userId ?? "空")") } } override func viewDidLoad() { super.viewDidLoad() print("viewDidLoad执行,当前userId:\(userId ?? "空")") // 你原来的fetchFeed()调用大概率在这里 } func fetchFeed() { print("fetchFeed执行,当前userId:\(userId ?? "空")") // 原有逻辑 }
- 执行跳转后看控制台输出顺序,如果是
viewDidLoad→fetchFeed→userId被赋值,就可以确认是时序问题
修复方案
方案1:修改为赋值后再触发数据请求
把fetchFeed()的调用移到userId的didSet里,保证只有userId有值的时候才会执行请求:
var userId: String? { didSet { // 只有userId不为空的时候才调用fetchFeed guard let userId = userId else { return } fetchFeed(userId: userId) } } // 把fetchFeed修改为接收参数,避免强制解包 func fetchFeed(userId: String) { let message = Database.database().reference().child("allmessages").child(currentUser).child(userId) // 原有后续逻辑 }
方案2:跳转前先获取数据,再触发segue
不要在prepare(for segue:)里做异步请求,而是先执行异步请求,拿到数据后再手动触发segue跳转,保证跳转时数据已经准备完成:
// 第一个控制器里,原来触发segue的按钮点击/事件响应处修改逻辑 func jumpToMessageVC() { if let ref = ref { DatabaseConnect.fetchTransactionUser(ref: ref, completion: { [weak self] (user) in guard let user = user else { return } // 拿到数据后再触发segue self?.performSegue(withIdentifier: "showMsg", sender: "Data passed") }) } } // prepare方法里直接传值即可 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showMsg" { let nav = segue.destination as! UINavigationController let VC = nav.topViewController as! MessagesViewController VC.userId = sender as? String } }
方案3:临时规避强制解包风险
如果不想改原有逻辑,至少把强制解包改成可选绑定,避免直接崩溃:
func fetchFeed() { guard let userId = userId else { print("userId还未准备完成,暂时不执行请求") return } let message = Database.database().reference().child("allmessages").child(currentUser).child(userId) // 原有后续逻辑 }
内容的提问来源于stack exchange,提问作者john smith
相关产品推荐
相关产品推荐

