I have issue with losing data in Core Data managed objects (all properties in spite of .objectID) are getting to be nil after going lockscreen and back.
I have been debugging this and found such issue.
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)
}
}
}
}
Having above simplifies code snipped it works ok. You can go lock the screen and go back and rows are reloaded with faulted core data managed objects.
But just adding ZStack, VStack, around ContactRow(contact: contact) breaks this and going lockscreen and then back again causes that list reloads with empty managed objects (with nil properties) and list is empty (if I am using optional unwrapping contact.name ?? "") or just crashes the app if I use fore unwrapping o like contact.name!
So this breaks
Changing my SimpleContactLists to this break the code like adding ZStack prevents refreshing list elements from database?
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)
}
UPDATE
contact NSManagedObject is empty but referencing self.contacts[i] IS NOT! Why?
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)
}
UPDATE 2
I have such solution. It helps in some List-from-FetchResults cases but is not desired solution in more complicated examples like List populated with managed objects in .sheet() (so here I need to stop presenting such 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()
}
}