我在丢失核心数据托管对象中的数据时遇到了问题(尽管使用了.objectID的所有属性)在锁屏并返回后都变为零。
我一直在调试它,发现了这样的问题。
struct SimpleContactsList: View {
@FetchRequest var contacts: FetchedResults<Contact>
let companyId: String
init(companyId: String) {
self.companyId = companyId
self._contacts = FetchRequest(
entity: Contact.entity(),
sortDescriptors: [
NSSortDescriptor(key: "name", ascending: true, selector: #selector(NSString.caseInsensitiveCompare(_:))),
NSSortDescriptor(keyPath: \Contact.createdAt, ascending: true)
],
predicate: NSPredicate(format: "company.id == %@", companyId)
)
}
var body: some View {
List {
ForEach(Array(self.contacts.enumerated()), id: \.1.objectID) { (i, contact) in
ContactRow(contact: contact)
}
}
}
}
以上内容简化了代码片段,可以正常工作。您可以锁定屏幕并返回,然后用有缺陷的核心数据托管对象重新加载行。
但是仅在ContactRow(contact:contact)周围添加ZStack,VStack会破坏此状态并进入锁屏状态,然后再次返回将导致列表重新加载具有空托管对象(具有nil属性)并且列表为空(如果我使用可选的解包) contact.name ??“”),或者如果我使用脱包o像contact.name一样只是崩溃了应用程序!
所以这打破了
将我的SimpleContactLists更改为此中断会像添加ZStack这样的代码阻止刷新数据库中的列表元素吗?
List {
ForEach(Array(self.contacts.enumerated()), id: \.1.objectID) { (i, contact) in
ZStack {
ContactRow(contact: contact)
}
.listRowBackground( (i%2 == 0) ? Color("DarkRowBackground") : .white)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.onDelete(perform: self.delete)
}
更新
联系人 NSManagedObject为空,但引用 self.contacts [i] 不是!为什么?
List {
ForEach(Array(self.contacts.enumerated()), id: \.1.objectID) { (i, contact) in
Button(action: {
self.selectedId = self.contacts[i].id!
self.showDetails = true
}) {
Contact(contact: contact)
//ContactRow(contact: self.contacts[i])
.background(Color.white.opacity(0.01))
}
.buttonStyle(ListButtonStyle())
.listRowBackground( (i%2 == 0) ? Color("DarkRowBackground") : .white)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.onDelete(perform: self.delete)
}
更新2
我有这样的解决方案。它在某些List-from-FetchResults情况下会有所帮助,但在更复杂的示例(例如在List中填充了.sheet()中的托管对象的解决方案)中不是理想的解决方案(因此,在这里,我需要停止显示此类工作表)
@State var theId = UUID()
List {
//rows
}
.id(theId)
.onReceive(appBecomeActivePublisher, perform: { _ in
self.theId = UUID()
}
extension UIApplication {
static var didBecomeActivePublisher: AnyPublisher<UIKit.Notification, Never> {
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
.eraseToAnyPublisher()
}
}
答案 0 :(得分:0)
这只是一个猜测,但是可能是因为您在enumerated()
中使用了ForEach
。如果您关心的是索引,请尝试使用该索引:
ForEach(0..<contacts.count, id: \.self) { i in
// rest appears to be the same
}
当您提取的结果更新时,这实际上将立即更新。
仅对此稍作扩展,但是FetchRequest
和FetchedResults
知道update()
,它们的意思是更新快速ui View
的{{1 }}。 body
不是,它只是一个简单的集合。因此,当发生更改时,您的enumerated()
不在乎,它还没有订阅更改。当body
发生更改时,您的FetchedResults
会执行,它会被 订阅,因此会自动更新并重新提供其内容。