英文:
SwiftUI not updating View after changing attribute value of a relationship entity
问题
我有两个核心数据实体,一个是"Deck",一个是"Card"。"Deck"与"Card"有关联关系(一个"Deck"对应多个"Card")。在SwiftUI中,当在不同屏幕更改"Card"的属性后,"Card"列表不会更新其视图以反映更改。
struct DeckDetailView: View {
@ObservedObject var deck: Deck
@State private var showSheet: Bool = false
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
Form {
ForEach(deck.cards?.allObjects as? [Card] ?? []) { card in
NavigationLink {
CardDetailView(card: card) { returnedCard in
updateCard(card: returnedCard)
}
} label: {
Text("Question: \(card.question)")
}
}
}
.navigationTitle("\(deck.name)")
.toolbar {
Button {
showSheet.toggle()
} label: {
Label("Add Deck", systemImage: "plus")
}
.sheet(isPresented: $showSheet) {
NavigationStack {
AddCardView { cardData in
addCard(cardData: cardData)
}
}
}
}
}
private func updateCard(card: Card) {
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
func addCard(cardData: CardSO) {
let card = Card(context: viewContext)
card.id = UUID().uuidString
card.question = cardData.question
card.answer = cardData.answer
deck.addToCards(card)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
英文:
I have two core data entities, a Deck and and Card. The Deck has a relationship with Card (one Deck to many Card). In SwiftUI after changing the attribute of Card in a different screen, the list of Card does not update its view to reflect the change.
struct DeckDetailView: View {
@ObservedObject var deck: Deck
@State private var showSheet : Bool = false
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
Form{
ForEach(deck.cards?.allObjects as? [Card] ?? []){ card in
NavigationLink {
CardDetailView(card: card) { returnedCard in
updateCard(card: returnedCard)
}
} label: {
Text("Question: \(card.question)")
}
}
}
.navigationTitle("\(deck.name)")
.toolbar{
Button {
showSheet.toggle()
} label: {
Label("Add Deck", systemImage: "plus")
}
.sheet(isPresented: $showSheet) {
NavigationStack{
AddCardView { cardData in
addCard(cardData: cardData)
}
}
}
}
}
private func updateCard(card: Card){
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
func addCard(cardData: CardSO){
let card = Card(context: viewContext)
card.id = UUID().uuidString
card.question = cardData.question
card.answer = cardData.answer
deck.addToCards(card)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
答案1
得分: 0
这是你要翻译的内容:
"Excellent question! I have faced this same issue many times. One of the ways, I ended up solving the issue is by using @FetchRequest property wrapper. I would pass Deck to the detail screen but use the Deck object to perform a new FetchRequest to get all the cards. When you use @FetchRequest<Card>, it will automatically track the changes.
I wrote a similar article on this issue that you can check out below:
https://azamsharp.com/2023/01/30/active-record-pattern-swiftui-core-data.html. See the section "Creating, Updating and Reading Reminders".
struct MyListDetailView: View {
let myList: MyList
@Environment(.managedObjectContext) private var viewContext
@FetchRequest(sortDescriptors: [])
private var reminderResults: FetchedResults<Reminder>
init(myList: MyList) {
self.myList = myList
_reminderResults = FetchRequest(fetchRequest: Reminder.byList(myList: myList))
}
extension Reminder: Model {
static func byList(myList: MyList) -> NSFetchRequest<Reminder> {
let request = Reminder.fetchRequest()
request.sortDescriptors = []
request.predicate = NSPredicate(format: "list = %@", myList)
return request
}
}"
希望这对你有所帮助。
英文:
Excellent question! I have faced this same issue many times. One of the ways, I ended up solving the issue is by using @FetchRequest property wrapper. I would pass Deck to the detail screen but use the Deck object to perform a new FetchRequest to get all the cards. When you use @FetchRequest<Card>, it will automatically track the changes.
I wrote a similar article on this issue that you can check out below:
https://azamsharp.com/2023/01/30/active-record-pattern-swiftui-core-data.html. See the section "Creating, Updating and Reading Reminders".
struct MyListDetailView: View {
let myList: MyList
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(sortDescriptors: [])
private var reminderResults: FetchedResults<Reminder>
init(myList: MyList) {
self.myList = myList
_reminderResults = FetchRequest(fetchRequest: Reminder.byList(myList: myList))
}
extension Reminder: Model {
static func byList(myList: MyList) -> NSFetchRequest<Reminder> {
let request = Reminder.fetchRequest()
request.sortDescriptors = []
request.predicate = NSPredicate(format: "list = %@", myList)
return request
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论