SwiftUI 在更改关联实体的属性值后未更新视图

huangapple go评论59阅读模式
英文:

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&lt;Reminder&gt;
    
    init(myList: MyList) {
        self.myList = myList
        _reminderResults = FetchRequest(fetchRequest: Reminder.byList(myList: myList))
    }

extension Reminder: Model {
    static func byList(myList: MyList) -&gt; NSFetchRequest&lt;Reminder&gt; {
        let request = Reminder.fetchRequest()
        request.sortDescriptors = []
        request.predicate = NSPredicate(format: &quot;list = %@&quot;, myList)
        return request 
    }
}

huangapple
  • 本文由 发表于 2023年2月14日 04:28:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75440863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定