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

SwiftUI技术问题:点击保存按钮后更新随机CoreData问题视图

解决SwiftUI点击保存后刷新随机问题的方案

看起来你已经离解决问题很近了!核心问题在于:你的currentQuestion是一个计算属性,虽然每次访问它都会返回新的随机值,但SwiftUI不会因为计算属性的变化自动刷新视图——只有当**状态变量(比如@State、@ObservedObject)**发生改变时,视图才会重新渲染。

下面是调整后的完整代码,我会一步步解释关键修改:

struct RecordView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Question.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Question.question, ascending: false)]) var questions: FetchedResults<Question>
    // 1. 用@State存储当前问题,这样修改它会触发视图刷新
    @State private var currentQuestion: String = ""
    @State private var newEntryText = ""
    
    var body: some View {
        VStack {
            Section(header: Text(currentQuestion)){
                TextField("New entry", text: self.$newEntryText)
                    .padding(100)
                HStack {
                    SwiftSpeech.RecordButton().scaleEffect(0.8).swiftSpeechToggleRecordingOnTap(locale: Locale(identifier: "de"), animation: .spring(response: 0.3, dampingFraction: 0.5, blendDuration: 0))
                        .onRecognize(update: self.$newEntryText)
                    Button(action: save) {
                        Image(systemName: "plus.circle.fill").foregroundColor(.green).imageScale(.large).scaleEffect(2.0)
                    }
                }
            }.automaticEnvironmentForSpeechRecognition()
        }
        // 2. 视图首次出现时,初始化随机问题(此时CoreData的数据已经加载完成)
        .onAppear {
            updateCurrentQuestion()
        }
    }
    
    func save() {
        let newEntry = Entry(context: self.moc)
        newEntry.text = self.newEntryText
        newEntry.createdAt = Date()
        do {
            try self.moc.save()
        }catch{
            print(error)
        }
        self.newEntryText = ""
        // 3. 保存完成后,更新当前问题,触发视图刷新
        updateCurrentQuestion()
        print(currentQuestion)
    }
    
    // 抽取出更新问题的逻辑,避免重复代码
    private func updateCurrentQuestion() {
        // 处理questions为空的情况,避免强制解包崩溃
        guard let randomQuestion = questions.randomElement()?.question else {
            currentQuestion = "No questions available"
            return
        }
        currentQuestion = randomQuestion
    }
}

关键修改点说明:

  • 用@State存储currentQuestion:@State是SwiftUI的核心状态管理工具,当它的值改变时,依赖它的视图会自动重新渲染。
  • onAppear初始化:视图首次出现时调用updateCurrentQuestion(),此时CoreData的questions已经完成加载,不会出现你之前遇到的"self未初始化"问题。
  • 保存后更新状态:在save()方法末尾调用updateCurrentQuestion(),这样每次保存答案后,都会生成新的随机问题并更新@State变量,触发视图刷新显示新问题。
  • 安全处理可选值:加入了guard let来避免questions为空时强制解包导致崩溃,提升了代码健壮性。

另外,你之前尝试的几种方案的问题也可以解释下:

  1. 直接用@State初始化时引用questions:因为属性初始化器在self创建前执行,此时questions还未被注入,所以报错。
  2. 计算属性:虽然每次访问都返回新值,但SwiftUI不会监测计算属性的变化,只有当它依赖的可观察对象(比如questions)发生增删改时才会刷新,但这里只是取随机元素,questions本身没有变化,所以视图不更新。
  3. lazy变量:lazy变量的getter是mutating的,而SwiftUI的View是值类型,在body中访问mutating方法会报错,因为body是只读环境。

这样应该就能完美实现你想要的"点击保存后显示新随机问题"的需求了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:47:36