使用 ForEach SwiftUI Core Data 仅更改列表中的一项

Posted

技术标签:

【中文标题】使用 ForEach SwiftUI Core Data 仅更改列表中的一项【英文标题】:Only change one item in List using ForEach SwiftUI Core Data 【发布时间】:2020-01-03 19:28:52 【问题描述】:

我有一个循环视图,使用 ForEeach 在使用 Core Data 关系的数组中显示列表。

视图显示了每个循环中的所有元素,我需要将它们单独分割出来,同时能够保持切换按钮而不是同时切换所有目标。

编辑:我想出了如何制作它,所以它们都没有迭代和显示,但现在切换任何按钮都会切换它们。 :(

游戏目标详情

import SwiftUI
import CoreData

struct GameGoalsDetail: View 
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Game.entity(), sortDescriptors: []) var games: FetchedResults<Game>

    @State private var showingAddGoal = false

    @State private var goalComplete : Bool = false

    @ObservedObject var game: Game

    var body: some View 
        VStack 
            Text(self.game.gameName ?? "No Game Name").font(.title)
            Text(self.game.gameDescription ?? "No Game Description").font(.subheadline)
            List GameGoalListView(game: self.game).environment(\.managedObjectContext, self.moc)
                
            Button("Add Game Goal") 
                self.showingAddGoal.toggle()
            
                .sheet(isPresented: $showingAddGoal) 
                    AddGameGoalsView(game: self.game).environment(\.managedObjectContext, self.moc)
            
        
    

游戏目标列表视图

import SwiftUI
import CoreData


struct GameGoalListView: View 

    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Game.entity(), sortDescriptors: []) var games: FetchedResults<Game>

    @ObservedObject var game: Game

    @State private var goalComplete : Bool = false


    var body: some View 
        VStack 
            ForEach(game.goalArray, id: \.self)  goal in
                HStack 
                    Text(goal.goalName ?? "No Goal Name")
                    Spacer()
                    Text("Complete:").font(.caption)
                    Image(systemName: self.goalComplete ? "checkmark.square.fill" : "app").onTapGesture 
                        self.goalComplete.toggle()
                        print(self.goalComplete)
                    
                
            
        

    

这是正在发生的事情的屏幕截图:

点击后:

我试图让它在添加目标时显示在列表中,然后我可以通过按钮选择目标是否完成。 所以每个游戏都会有一个由用户输入添加的不同目标的列表。

非常感谢帮助并可以根据要求提供更多信息。

【问题讨论】:

您需要添加更多上下文。很难理解你在这里问什么,更不用说你的代码应该做什么了。 @Pierce 我添加了更多上下文。看看 Core Data 类会有帮助吗? 现在我有点理解您想要做什么,但我不一定理解您在尝试执行此操作时遇到的问题。我不知道展示你的 CD 课程是否真的有帮助,我的直觉认为这并不重要,听起来你的逻辑或 UI 的设置方式可能有问题? 您正在外部和内部视图中迭代目标列表。你不想要这些循环之一吗?你能展示一下输出应该是什么样子吗? @Paulw11 我对其进行了编辑,以便仅迭代内部视图,但现在所有项目都被切换,而不仅仅是一个。 【参考方案1】:

我不得不重做这么多,但在一位出色的 Redditor 的帮助下,我弄明白了。

游戏目标详情

我不需要获取请求,因为它是从视图中传入的。 不需要@State,因为我应该直接使用 CoreData 信息。
List 
    ForEach(game.goalArray, id: \.self)  goal in
        GameGoalListView(goal: goal)
    

只需要传入的GameGoalListView(goal:goal),因为我重做了GameGoalListView。

游戏目标列表视图

再次摆脱了@State 和@FetchRequest GameGoalsDetail 中的列表是显示每个目标的内容,因此此视图中不需要额外的 ForEach。此视图只需要显示需要显示的内容以及从 CoreData 中提取的信息。

@ObservedObject 是目标而不是游戏。 onTapGesture 正在从 CoreData 而不是状态访问goal.goalComplete(这会创建一个新的真相来源(观看 WDCC 视频))。

然后 onReceive 和 objectWillChange 让目标知道每次点击按钮时它都会发生变化。

struct GameGoalListView: View 
    
    @Environment(\.managedObjectContext) var moc
    
    @ObservedObject var goal: Goal
    
    var body: some View 
        VStack 
            HStack 
                Text(goal.goalName ?? "No Goal Name")
                Spacer()
                Text("Complete:").font(.caption)
                Image(systemName: self.goal.goalComplete ? "checkmark.square.fill" : "app").onTapGesture 
                    self.goal.goalComplete.toggle()
                    print(self.goal.goalComplete)
                
            
        
        .onReceive(self.goal.objectWillChange) 
            try? self.moc.save()
        
    

正如我所说,帮助来自 Redditor,我希望这可以帮助某人找出我的问题并修复他们的错误。

【讨论】:

谢谢,这正是我想要的。很好的解决方案! for id: \.self 你能用\.objectID代替吗?

以上是关于使用 ForEach SwiftUI Core Data 仅更改列表中的一项的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 将 Core Data 实体读入 []

在 SwiftUI 中,如何在 LinkedList 中“Foreach”节点?

swiftui删除核心数据行

如何使用 SwiftUI 使这个 ForEach 函数工作?

如何在 SwiftUI 中使用 Foreach 视图?

SwiftUI 中的 ForEach