iOS问题:App退至后台时List选中状态被重置为nil
问题解决:App后台后List选中状态被重置为nil
问题根源
你遇到的问题不是StateObject的问题,而是数据源实例一致性导致的:
SidebarView内部定义的private let persons,每次视图重建(App从后台切回前台时会触发视图刷新)都会生成全新的Person实例集合。- 虽然新实例的
id和firstname和旧实例一致,但它们是内存中不同的对象。 List使用id:\.self依赖Person的默认Hashable实现(结构体默认基于所有属性做哈希和相等判断),后台回来后,原selectedPerson是旧实例,和新persons里的实例无法匹配,List就会自动将选中状态重置为nil。
解决方案
方案一:统一数据源到AppModel(推荐)
把persons数据源移到AppModel中,确保整个App生命周期内只有一份实例,从根源上避免实例不一致问题:
class AppModel: ObservableObject { @Published var selectedPerson: Person? // 全局唯一的数据源 let persons = [Person(firstname: "Joe"), Person(firstname: "Jane")] } struct SidebarView: View { @EnvironmentObject private var appModel: AppModel var body: some View { List(appModel.persons, id:\.self, selection: $appModel.selectedPerson) { person in Text(person.firstname).tag(person) } .listStyle(.sidebar) } }
方案二:自定义Person的相等判断逻辑
如果必须在视图内定义数据源,可以修改Person的Hashable和Equatable实现,只基于唯一标识id来判断对象是否相等:
struct Person: Identifiable, Hashable { let id: UUID let firstname: String init(firstname: String) { id = UUID() self.firstname = firstname } // 仅通过id判断相等 static func == (lhs: Person, rhs: Person) -> Bool { lhs.id == rhs.id } // 仅基于id生成哈希值 func hash(into hasher: inout Hasher) { hasher.combine(id) } }
这样即使视图重建生成新的Person实例,只要id相同,就会被List识别为同一个对象,选中状态就能保留。
补充说明
StateObject确实能保证AppModel的实例不会被销毁重建,但你的问题核心是数据源实例的一致性,和StateObject的工作机制无关,这属于SwiftUI视图刷新时的常见逻辑问题,不是Bug。
内容的提问来源于stack exchange,提问作者GSD
相关产品推荐
相关产品推荐

