You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:05:33