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为空时强制解包导致崩溃,提升了代码健壮性。
另外,你之前尝试的几种方案的问题也可以解释下:
- 直接用@State初始化时引用
questions:因为属性初始化器在self创建前执行,此时questions还未被注入,所以报错。 - 计算属性:虽然每次访问都返回新值,但SwiftUI不会监测计算属性的变化,只有当它依赖的可观察对象(比如questions)发生增删改时才会刷新,但这里只是取随机元素,questions本身没有变化,所以视图不更新。
- lazy变量:lazy变量的getter是mutating的,而SwiftUI的View是值类型,在body中访问mutating方法会报错,因为body是只读环境。
这样应该就能完美实现你想要的"点击保存后显示新随机问题"的需求了!
内容的提问来源于stack exchange,提问作者niklasd
相关产品推荐
相关产品推荐

