在其他视图中更新核心数据属性时,SwiftUI 列表不会更新

rv7*_*284 4 core-data ios swiftui swiftui-list

@State var documents: [ScanDocument] = []

func loadDocuments() {
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }
    
    let managedContext =
        appDelegate.persistentContainer.viewContext
    
    let fetchRequest =
        NSFetchRequest<NSManagedObject>(entityName: "ScanDocument")
    
    do {
        documents = try managedContext.fetch(fetchRequest) as! [ScanDocument]
        print(documents.compactMap({$0.name}))
    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }
}
Run Code Online (Sandbox Code Playgroud)

在第一个视图中:

.onAppear(){
     self.loadDocuments()
 }
Run Code Online (Sandbox Code Playgroud)

现在我正在推动详细查看单个对象:

NavigationLink(destination: RenameDocumentView(document: documents[selectedDocumentIndex!]), isActive: $pushActive) {
                    Text("")
                }.hidden()
Run Code Online (Sandbox Code Playgroud)

在重命名文档视图中:

var document: ScanDocument
Run Code Online (Sandbox Code Playgroud)

此外,还有一个更新文档名称的函数:

func renameDocument() {
    guard !fileName.isEmpty else {return}
    document.name = fileName
    try? self.moc.save()
    print(fileName)
    self.presentationMode.wrappedValue.dismiss()
}
Run Code Online (Sandbox Code Playgroud)

所有这些代码都有效。此打印语句始终打印更新的值:

print(documents.compactMap({$0.name}))
Run Code Online (Sandbox Code Playgroud)

这是主视图中的列表代码:

List(documents, id: \.id) { item in
     ZStack {
          DocumentCell(document: item)
     }
}
Run Code Online (Sandbox Code Playgroud)

但是用户回到上一个屏幕的地方。该列表显示旧数据。如果我重新启动应用程序,它会显示新数据。

任何推动新方向的帮助都会有所帮助。

这里有一个类似的问题:SwiftUI List View not updated after Core Data entity updated in another View,但没有答案。

Asp*_*eri 6

NSManagedObject是一种引用类型,因此当您更改其属性时,您documents不会更改,因此状态不会刷新视图。

这是您回来时强制刷新列表的可能方法

  1. 添加新状态
@State var documents: [ScanDocument] = []
@State private var refreshID = UUID()   // can be actually anything, but unique
Run Code Online (Sandbox Code Playgroud)
  1. 制作由它标识的列表
List(documents, id: \.id) { item in
     ZStack {
          DocumentCell(document: item)
     }
}.id(refreshID)     // << here
Run Code Online (Sandbox Code Playgroud)
  1. 回来时更改refreshID,以便强制重建列表
NavigationLink(destination: RenameDocumentView(document: documents[selectedDocumentIndex!])
                               .onDisappear(perform: {self.refreshID = UUID()}), 
                isActive: $pushActive) {
                    Text("")
                }.hidden()
Run Code Online (Sandbox Code Playgroud)

替代:可能的替代方法是制作DocumentCell观察文件,但没有提供代码,所以不清楚里面是什么。反正你可以试试

struct DocumentCell: View {
   @ObservedObject document: ScanDocument
 
   ...
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*Nik 5

改变

var document: ScanDocument
Run Code Online (Sandbox Code Playgroud)

@ObservedObject var document: ScanDocument
Run Code Online (Sandbox Code Playgroud)