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

如何在SwiftUI应用中持久化保存用户输入内容?

SwiftUI实现用户输入内容持久化(重启/返回后保留)

你的当前代码里,@State变量仅存在于内存中,应用重启或视图销毁后数据就会丢失,必须添加磁盘持久化逻辑才能让内容留存。下面给你两种实用的实现方案:

方案一:用@AppStorage直接处理数组持久化

@AppStorage是SwiftUI自带的轻量持久化工具,支持存储Data类型,我们可以通过JSON编解码把字符串数组转成Data存储:

修改原代码中的landings变量部分,替换成以下代码:

// 用Data类型存储数组的JSON编码结果
@AppStorage("landings") private var landingsData: Data = Data()
// 计算属性,负责编解码数组
private var landings: [String] {
    get {
        (try? JSONDecoder().decode([String].self, from: landingsData)) ?? []
    }
    set {
        landingsData = (try? JSONEncoder().encode(newValue)) ?? Data()
    }
}

然后调整添加和更新逻辑的代码:

  • 添加按钮的逻辑:
Button("Add") {
    if !newLandingName.isEmpty {
        // 因为landings是计算属性,需要重新赋值触发存储
        landings = landings + [newLandingName]
        newLandingName = ""
    }
    isAddingLanding = false
}
  • 更新按钮的逻辑(顺便修复原代码里的冗余写法):
Button("Update") {
    if !newLandingName.isEmpty {
        if let idx = landings.firstIndex(where: { $0 == oldLandingName }) {
            var updatedLandings = landings
            updatedLandings[idx] = newLandingName
            landings = updatedLandings
        }
    }
    isEditing = false
}

方案二:用ViewModel管理持久化(更适合扩展)

如果以后需要添加更多复杂逻辑,建议把数据管理抽成ViewModel,代码结构更清晰:

首先创建ViewModel类:

class LandingViewModel: ObservableObject {
    @Published var landings: [String] = []
    private let defaultsKey = "saved_landings"
    
    init() {
        // 初始化时读取本地存储的数据
        loadSavedLandings()
    }
    
    // 从UserDefaults读取数据
    private func loadSavedLandings() {
        guard let data = UserDefaults.standard.data(forKey: defaultsKey),
              let savedLandings = try? JSONDecoder().decode([String].self, from: data) else {
            return
        }
        landings = savedLandings
    }
    
    // 保存数据到UserDefaults
    private func saveLandings() {
        guard let data = try? JSONEncoder().encode(landings) else {
            return
        }
        UserDefaults.standard.set(data, forKey: defaultsKey)
    }
    
    // 添加新条目
    func addNewLanding(_ name: String) {
        landings.append(name)
        saveLandings()
    }
    
    // 更新条目
    func updateLanding(oldName: String, newName: String) {
        guard let index = landings.firstIndex(of: oldName) else {
            return
        }
        landings[index] = newName
        saveLandings()
    }
}

然后在View中使用ViewModel:

struct LandingView: View {
    @State private var oldLandingName: String = ""
    @State private var newLandingName: String = ""
    @State private var isAddingLanding = false
    @State private var isEditing = false
    // 使用@StateObject持有ViewModel
    @StateObject private var viewModel = LandingViewModel()
    
    var body: some View {
        NavigationView {
            // ... 其他界面代码不变,只修改列表和按钮逻辑 ...
            
            List(viewModel.landings, id: \.self) { landing in
                Text(landing).bold()
                    .foregroundColor(.white)
                    .listRowBackground(Color.clear)
                    .listRowSeparatorTint(.blue)
                    .onTapGesture {
                        self.isEditing = true
                        self.oldLandingName = landing
                        self.newLandingName = landing
                    }
            }
            
            // 添加界面的按钮
            Button("Add") {
                if !newLandingName.isEmpty {
                    viewModel.addNewLanding(newLandingName)
                    newLandingName = ""
                }
                isAddingLanding = false
            }
            
            // 更新界面的按钮
            Button("Update") {
                if !newLandingName.isEmpty {
                    viewModel.updateLanding(oldName: oldLandingName, newName: newLandingName)
                }
                isEditing = false
            }
            
        }
    }
}

注意点

  • 这两种方案都用了UserDefaults,适合存储少量数据(比如这种字符串数组);如果以后需要存储大量复杂数据,建议改用Core Data或Realm。
  • 原代码中更新按钮里的$oldLandingName.wrappedValue是冗余写法,直接用oldLandingName即可。

内容的提问来源于stack exchange,提问作者allanrulezdood

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:18:10