Eu tenho um caso de uso simples em que tenho um modelo Core Data com um Item
(que possui uma propriedade 'timestamp') e um relacionamento um-para-um com Tag
(que possui uma propriedade 'tagName'). Quero usar o SwiftUI para mostrar uma lista de itens e, em cada linha, mostro o carimbo de data/hora do item e o tag.tagName, se estiver disponível.
O problema que estou enfrentando é que, se eu atualizar o tagName associado a um item, ele não será atualizado automaticamente na visualização do SwiftUI. Quaisquer atualizações serão Item
atualizadas automaticamente e, se eu reiniciar o aplicativo, ele também receberá as alterações... mas isso não acontece automaticamente.
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationView {
List {
Section {
ForEach(items) { item in
VStack (alignment: .leading){
Text(item.timestamp!, formatter: itemFormatter)
if let tag = item.tag, let name = tag.tagName {
Text("Tag: \(name)")
}
}
}
.onDelete(perform: deleteItems)
} header: {
Text("Items")
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
ToolbarItem (placement: .navigationBarLeading) {
Button(action: addTagItem) {
Label("Add Tag", systemImage: "tag")
}
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: editTagItem) {
Label("Change Tag Name", systemImage: "phone")
}
}
}
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
try? viewContext.save()
}
}
private func addTagItem() {
withAnimation {
let newItem = Tag(context: viewContext)
newItem.tagName = "Design"
if let item = items.first {
item.tag = newItem
}
try? viewContext.save()
}
}
private func editTagItem() {
withAnimation {
if let item = items.first, let tag = item.tag {
tag.tagName = "changed"
}
try? viewContext.save() // <-- should update the List, but doesn't
if let item = items.first, let tag = item.tag {
tag.objectWillChange.send() // tried this, doesn't work
}
}
}
}
Adicionei botões da barra de ferramentas para testar o cenário de adicionar um novo item, uma nova tag e definir a tag do primeiro item para a primeira tag e depois um para alterar o nome da tag. As duas primeiras funções funcionam bem, mas alterar o tagName não atualiza a visualização da lista.
Parece que o SwiftUI @FetchRequest
está ouvindo apenas alterações Item
. Acho que é semelhante ao NSFetchedResultsController
que faria o mesmo, mas esperava que o SwiftUI melhorasse essa situação. Em outras questões que olhei, objectWillChange.send
parece ajudar, mas não parece resolver o meu problema.
De qualquer forma, qual é a melhor maneira de atualizar a lista completa se uma propriedade de relacionamento for alterada?
Apenas use
@ObservedObject var tag: Tag