问题
I'm trying to figure out what I can possibly be doing wrong (or, of course, misunderstood about relationships, fetches and all).
In a first search, when I read the question's title, I hoped this question could help me, but I was wrong:
SwiftUI TabView with List not refreshing after objected deleted from / added to Core Data
Anyway...
In my app, when I touch a customer item, the detail view is shown properly with its data. If I change any attribute and go back to the first view, its updated correctly.
My problems start when I add a new location or delete one of the existing ones. When I go back to first view, the number of consumer's existing locations is not updated. When I close and reopen the app, all the data is correctly show.
As I said, my Core Data's model has 2 entities, like this:
Entity: Customer id: String name: String locationList: [Location] (to-many (Location), cascade)
Entity: Location id: String addess: String fromCustomer: Customer (to-One (Customer), nullify)
This is the view witch shows the Customers list:
struct CustomerList: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(
entity: Customer.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Customer.name, ascending: true),
]
) var customerList: FetchedResults<Customer>
var body: some View {
VStack{
CustomerArea
}
.navigationBarTitle(Text("Customers"), displayMode: .inline)
.navigationBarItems(leading: btnCreate, trailing: btnNew)
}
var CustomerArea: some View {
List{
ForEach(customerList, id: \.id) { customer in
NavigationLink(
destination: LocationList(selectedCustomer: customer)
) {
VStack(alignment: .leading){
Text("\(customer.name ?? "?")").font(.headline)
HStack{
Spacer()
Text("Locations: \(customer.locationList?.count ?? 0)")
.font(.footnote)
}
}.padding()
}
}.onDelete(perform: self.removeCustomer)
}
}
private func removeCustomer(at offsets: IndexSet) {
for index in offsets {
let obj = customerList[index]
self.moc.delete(obj)
}
try? self.moc.save()
}
}
Finally, this is my LocationList view:
struct LocationList: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@Environment(\.managedObjectContext) var moc
var requestLocations : FetchRequest<Location>
var locationList : FetchedResults<Location>{requestLocations.wrappedValue}
var selectedCustomer: Customer
init(selectedCustomer: Customer){
self.selectedCustomer = selectedCustomer
self.requestLocations = FetchRequest(
entity: Location.entity(),
sortDescriptors: [],
predicate: NSPredicate(format: "fromCustomer.id == %@", selectedCustomer.id!)
)
}
var btnNewLocation : some View { Button(action: {
let object = Location(context: self.moc)
object.id = UUID().uuidString
object.address = UUID().uuidString
object.fromCustomer = self.selectedCustomer
try? self.moc.save()
}) {
Image(systemName: "plus.circle.fill")
}
}
var body: some View {
VStack{
List{
ForEach(locationList, id: \.id) { location in
VStack(alignment: .leading){
Text("\(location.address ?? "?")").font(.headline)
.onTapGesture {
print("Tapped and changed selected parent object")
self.selectedCustomer.name = "Changed"
try? self.moc.save()
self.presentationMode.wrappedValue.dismiss()
}
}.padding()
}
.onDelete(perform: removeLocation)
}
}
.navigationBarTitle(Text("\(selectedCustomer.name ?? "?")"), displayMode: .inline)
.navigationBarItems(trailing: btnNewLocation)
}
private func removeLocation(at offsets: IndexSet) {
for index in offsets {
let obj = locationList[index]
self.moc.delete(obj)
}
try? self.moc.save()
}
}
This is the first view. Imagine I touched the last item:
There's no locations linked to the selected customer:
So, I added on new item:
The number of locations is still ZERO, but should be 1:
回答1:
A huge surprise in iOS: core data controllers only work on basic fields. Strange but true.
Incredibly, CoreData does not update based on relationships.
Only basic fields (int, string, etc).
You can see many QA and articles about this bizarre issue, example:
NSFetchedResultsController with relationship not updating
It is "just how it is".
There have been many attempts to work around this bizarre situation. There is no real solution. NSFetchedResultsController "is what it is" - it only works on basic fields (string, int, etc).
Unfortunately that is the situation.
Note: if I misunderstand the question here, sorry. But I believe this is the issue.
来源:https://stackoverflow.com/questions/62374472/swiftui-core-data-does-not-refresh-one-to-many-relations-properly-and-lists-ar