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

SwiftUI调用clear函数后ItemView未刷新问题求助

问题:调用clear函数后ItemView未自动刷新

调用clear函数后,CoreData的增删操作都正常执行,但ItemView不会自动刷新,必须关闭并重新打开History视图才能看到新增的"Clear"记录。不清楚问题出在哪,求解决思路,是否需要添加.onAppear()?


HistoryView 代码

import SwiftUI

struct HistoryView: View {
    @Environment(\.MOC) private var viewContext
    var card: FetchedResults<Card>.Element

    var body: some View {
        ScrollView {
            VStack() {
                // Something here!
                Group {
                    // Something here!
                    HStack() {
                        // Something here!
                        Button(action: { clear() }, label: { Text("Clear") })
                    }
                }
                VStack() {
                    ForEach(card.elementArray) { element in
                        ItemView(element: element)
                        Divider()
                    }
                }
            }
        }
    }

    private func clear() { CoreData.shared.clearHistory(card: card, context: viewContext) }
}

struct ItemView: View {
    var element: FetchedResults<Element>.Element

    var body: some View {
        HStack() {
            Text(element.date!, format: .dateTime.day(.twoDigits).month(.twoDigits))
            Spacer()
            if element.designation == "Create" { Text("Create") }
            // Something here!
            else if element.designation == "Clear" { Text("Clear") }
        }
    }
}

extension Card {
    public var elementArray: [Element] {
        let set = element as? Set<Element> ?? []
        return set.sorted {
            $0.date! > $1.date!
        }
    }
}

CoreData 管理器的 clearHistory 函数

func clearHistory(card: Card, context: NSManagedObjectContext) {
    card.elementArray.forEach {
        context.delete($0)
    }
    let element = Element(context: context)
    // Something here!
    element.designation = "Clear"
    element.card = card
    save(context: context)
}

解决思路

  1. 问题本质:SwiftUI的ForEach需要能被监听的数据源才会触发视图刷新。你当前用的card.elementArray是自定义计算属性,返回的是普通数组——即便CoreData里的element集合发生变化,这个计算属性的变动无法被SwiftUI感知,自然不会刷新视图。

  2. 最优修复方案:直接用CoreData的FetchedResults驱动ForEach,替代自定义数组:

    • 给HistoryView添加针对当前Card关联Element的FetchRequest:
      @FetchRequest private var elements: FetchedResults<Element>
      
      init(card: FetchedResults<Card>.Element) {
          self.card = card
          _elements = FetchRequest<Element>(
              sortDescriptors: [NSSortDescriptor(keyPath: \Element.date, ascending: false)],
              predicate: NSPredicate(format: "card == %@", card)
          )
      }
      
    • 替换原有的ForEach数据源:
      ForEach(elements) { element in
          ItemView(element: element)
          Divider()
      }
      

    这样CoreData的数据变化会自动通知FetchedResults,进而触发SwiftUI视图刷新,不需要手动添加.onAppear()。

  3. 为什么自定义数组不行:计算属性elementArray每次访问都会生成新数组,即便内容变化,它既不是@Published/Observable类型,也不是CoreData自带的可监听集合,SwiftUI无法追踪其变化。

  4. 备选方案(不推荐):如果一定要保留elementArray,可以让Card遵循ObservableObject,并在element集合变动时发送objectWillChange通知,但这种做法比直接用FetchRequest繁琐且可靠性更低。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:22:33