·
#iOS#SwiftUI#踩坑
SwiftUI 里 Service 千万别用 @State
iOS 新手踩坑:每次重新进页面 Service 都「重置」了,原因是 @State 的生命周期不是你以为的那样
iOS 是我的知识盲区,写 ClawMo 的时候踩了一个不算 bug 的 bug,记一下。
问题
管理页有一个 WebSocketService,负责长连接和会话同步。最初我这么写:
struct AdminPage: View {
@State private var service = WebSocketService()
// ...
}
结果每次切到别的 tab 再回来,连接就重连一次、会话列表清空、用户登录态丢失。
原因
@State 是绑定在 当前 View 实例 的存储。SwiftUI 在父视图重建(比如 tab 切换)时,View struct 会被重新创建,@State 的初值会被重新求值——但只在第一次有效,之后由框架托管。
听起来好像没问题,但如果你把 Service 当成「计算属性」或者用 @State 持有一个非 ObservableObject、又不走 EnvironmentObject 注入,行为就会很微妙:在某些重建场景下,框架会判定它需要重置。
正解
Service 必须是单例 + let,View 只持有引用:
final class WebSocketService: ObservableObject {
static let shared = WebSocketService()
// ...
}
struct AdminPage: View {
let service = WebSocketService.shared
// ...
}
或者顶层用 EnvironmentObject 注入。关键点是:Service 的生命周期不能跟 View 的生命周期绑定。
教训
- SwiftUI 的属性包装器有一套自己的生命周期模型,不要按 React
useState的直觉去用 - 长连接、登录态、缓存这种「应用级状态」,永远走单例或 Environment
- 写 Swift 多让 Claude 解释一下原理,省下来的时间够再写一个页面