[英]SwiftUI List not updating when core data property is updated in other view
@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)")
}
}
在第一個視圖中:
.onAppear(){
self.loadDocuments()
}
現在我要詳細查看單個 object:
NavigationLink(destination: RenameDocumentView(document: documents[selectedDocumentIndex!]), isActive: $pushActive) {
Text("")
}.hidden()
在重命名文檔視圖中:
var document: ScanDocument
另外,一個 function 更新文檔名稱:
func renameDocument() {
guard !fileName.isEmpty else {return}
document.name = fileName
try? self.moc.save()
print(fileName)
self.presentationMode.wrappedValue.dismiss()
}
所有這些代碼都有效。 此打印語句始終打印更新的值:
print(documents.compactMap({$0.name}))
這是主視圖中的列表代碼:
List(documents, id: \.id) { item in
ZStack {
DocumentCell(document: item)
}
}
但是用戶回到前一個屏幕的地方。 該列表顯示舊數據。 如果我重新啟動應用程序,它會顯示新數據。
向新方向輕推的任何幫助都會有所幫助。
這里有一個類似的問題: SwiftUI List View not updated after Core Data entity updated in another View ,但沒有答案。
NSManagedObject
是一種引用類型,因此當您更改其屬性時,您的documents
不會更改,因此 state 不會刷新視圖。
這是您回來時強制刷新列表的一種可能方法
@State var documents: [ScanDocument] = []
@State private var refreshID = UUID() // can be actually anything, but unique
List(documents, id: \.id) { item in
ZStack {
DocumentCell(document: item)
}
}.id(refreshID) // << here
NavigationLink(destination: RenameDocumentView(document: documents[selectedDocumentIndex!])
.onDisappear(perform: {self.refreshID = UUID()}),
isActive: $pushActive) {
Text("")
}.hidden()
替代:可能的替代是讓DocumentCell
觀察文檔,但沒有提供代碼,因此不清楚里面是什么。 反正你可以試試
struct DocumentCell: View {
@ObservedObject document: ScanDocument
...
}
改變:
var document: ScanDocument
至:
@ObservedObject var document: ScanDocument
Core Data 批量更新不會更新內存中的對象。 之后您必須手動刷新。
批處理操作繞過正常的核心數據操作並直接在底層 SQLite 數據庫(或任何支持您的持久存儲)上操作。 他們這樣做是為了提高速度,但這意味着他們也不會觸發您使用正常獲取請求獲得的所有內容。
您需要執行 Apple 的核心數據批處理編程指南中所示的操作:實施批處理更新 - 執行后更新您的應用程序
let request = NSBatchUpdateRequest(entity: ScanDocument.entity())
request.resultType = .updatedObjectIDsResultType
let result = try viewContext.execute(request) as? NSBatchUpdateResult
let objectIDArray = result?.result as? [NSManagedObjectID]
let changes = [NSUpdatedObjectsKey: objectIDArray]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedContext])
嘗試提供此問題的解決方案時,另一個考慮因素與類型定義和您將獲取請求結果強制轉換為ScanDocument
object 數組(即[ScanDocument]
)有關。
你的代碼行...
documents = try managedContext.fetch(fetchRequest) as! [ScanDocument]
...正在try
強制將您的var documents
向下轉換為這種類型 - 一個對象數組。
事實上,一個NSFetchRequest
本身返回一個NSFetchRequestResult
,但是您已經定義了您期望從var documents
中獲得的類型。
在我的代碼中定義對象數組的類似示例中,我省略了強制向下轉換,然后try
將NSFetchRequestResult
作為已定義的ScanDocument
object 數組返回。
所以這應該工作......
documents = try managedContext.fetch(fetchRequest)
另外我注意到您正在使用 SwiftUI List
...
評論 1
所以你可以試試這個...
List(documents, id: \.id) { item in
ZStack {
DocumentCell(document: item)
}
.onChange(of: item) { _ in
loadDocuments()
}
}
(注:未經測試)
但更重要的是...
評論 2
您是否有理由不使用@FetchRequest
或@SectionedFetchRequest
視圖構建器? 這些中的任何一個都將大大簡化您的代碼並使生活變得更加有趣。
例如...
@FetchRequest(entity: ScanDocument.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \.your1stAttributeAsKeyPath, ascending: true),
NSSortDescriptor(keyPath: \.your2ndAttributeAsKeyPath, ascending: true)
] // these are optional and can be replaced with []
) var documents: FetchedResults<ScanDocument>
List(documents, id: \.id) { item in
ZStack {
DocumentCell(document: item)
}
}
因為 SwiftUI 中的所有核心數據實體默認都是ObservedObject
並且也符合Identifiable
協議,所以您也可以在列表中省略id
參數。
例如...
List(documents) { item in
ZStack {
DocumentCell(document: item)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.