父对象的核心数据列表关系

Posted

技术标签:

【中文标题】父对象的核心数据列表关系【英文标题】:Core Data list relationship of Parent Object 【发布时间】:2020-08-22 09:28:04 【问题描述】:

我有两个核心数据实体。一种叫做“程序”,一种叫做“锻炼”。程序与运动是一对多的关系。

我在另一个视图中将练习添加到程序中。 我有一个列出所有程序的视图和一个指向该视图的导航链接。

在这个视图中,我想列出我之前分配给程序的所有练习。但是,如果我尝试此代码,我会收到错误消息:Generic struct 'ForEach' requires that 'Exercise' conform to 'RandomAccessCollection'。

我是核心数据关系的新手,我想我可能忘记在 CoreDataClass 文件中声明某些内容。问题是我找不到这个问题的任何其他解决方案。

struct ProgramView: View 

@ObservedObject var ProgramDetail: Program

var body: some View 
            List 
                ForEach(ProgramDetail.exercise!, id: \.self)  exercise in
                    Text(exercise.name!)
                
         

这会生成所有程序的列表:

struct ProgramList: View 
    @Environment(\.managedObjectContext) var viewContext
    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Program.date, ascending: false)]) var programFetch: FetchedResults<Program>

    
    var body: some View 
        NavigationView 
                List 
                    ForEach(programFetch, id: \.self)  program in 
                        NavigationLink(destination: ProgramView(ProgramDetail: program))  
                            Text(program.title!)
                        
                    
                .navigationBarItems(
                    trailing:
                        NavigationLink(destination: CreateProgram()) 
                            Image(systemName: "plus.circle").font(.system(size: 25))
                        )
      

这是界面截图?:

Interface

【问题讨论】:

【参考方案1】:

错误消息说明您必须有一个随机访问集合,以便ForEach 可以遍历该集合。

例如,Swift 的Array 符合RandomAccessCollection 协议,因此您可以使用数组。

我建议您在 Swift documentation 或 Apple's Developer website 上阅读收藏。

可能有几种方法可以实现解决方案,但也许最简单的方法如下......

struct ProgramView: View 
    
    @ObservedObject var programDetail: Program
    
    @FetchRequest(entity: Exercise.entity(),
                  sortDescriptors: [NSSortDescriptor(keyPath: \Exercise.name, ascending: true)],
    ) var allExercises: FetchedResults<Exercise>
    
    var body: some View 
        List 
            // in this line you create an array of fetched results
            // filtered to contain only exercises for programDetail
            let exercisesForProgram = allExercises.filter  $0.program == programDetail 
            
            ForEach(exercisesForProgram)  exercise in
                Text(exercise.name!)
            
        
    

【讨论】:

是的!这解决了我的问题。现在来测试它是否会将更改保存回 Core Data 对象... @FontFamily 它为我保存了更改。【参考方案2】:

假设您没有将 To Many 关系的安排更改为 Ordered,ProgramDetail.exerciseNSSet?

您可以定义一个计算属性以将其转换为 Exercise 的数组:

extension Program 
    var exerciseArray: [Exercise] 
        let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
        return exercise?.sortedArray(using: [sortDescriptor]) as? [Exercise] ?? [Exercise]()
    

ProgramView 现在您可以使用数组创建您的列表,如下所示:

List 
    ForEach(programDetail.exerciseArray, id: \.self)  exercise in
        Text("\(exercise.name ?? "")")
    

如果练习是有序关系,则ProgramDetail.exercise 将是NSOrderedSet?

在这种情况下,练习数组的定义就更简单了:

var exerciseArray: [Exercise] 
    return exercise?.array as? [Exercise] ?? [Exercise]()

【讨论】:

以上是关于父对象的核心数据列表关系的主要内容,如果未能解决你的问题,请参考以下文章

RestKit、核心数据和关系问题。父对象不识别子集

核心数据模型级联删除和父实体

从核心数据获取请求中排除反向关系

与核心数据的关系错误

在不获取现有对象的情况下创建核心数据关系

在核心数据中保存动态生成的带有父->子关系的JSON数据?