Ios 更新数据模型时将插入数组作为关系对象存储

Ios 更新数据模型时将插入数组作为关系对象存储,ios,swift,core-data,corestore,Ios,Swift,Core Data,Corestore,我有下一个代码来更新我的训练: func addMuscleGroups(muscleGroups: [MusclEntity], toWorkout: WorkoutEntity, completion: @escaping (ResultInfo<WorkoutEntity>) -> Void) { CoreStore.perform( asynchronous: { (transaction) -> WorkoutEntit

我有下一个代码来更新我的训练:

func addMuscleGroups(muscleGroups: [MusclEntity], toWorkout: WorkoutEntity, completion: @escaping (ResultInfo<WorkoutEntity>) -> Void) {

        CoreStore.perform(
            asynchronous: { (transaction) -> WorkoutEntity? in
                let workout = transaction.edit(toWorkout)!

                for muscle in muscleGroups {
                    let editedMuscle = transaction.edit(muscle)!
                    workout.muscles?.insert(editedMuscle)
                }

                return workout
        },

            success: { (transactionWorkout) in // here we have muscles for transactionWorkout

                guard let unwrappedTransactionWorkout = transactionWorkout else {
                    return
                }

                let workout = CoreStore.fetchExisting(unwrappedTransactionWorkout) // there are no muscles objects

                guard let unwrappedWorkout = workout else {
                    return
                }

                completion(.data(unwrappedWorkout))
        },
            failure: { (error) in
                completion(.error(StackedError.internalFetchingDataError(message: error.debugDescription)))
        })

    }
func addMuscleGroups(muscleGroups:[MusclEntity],toWorkout:WorkoutEntity,completion:@escaping(ResultInfo)->Void){
CoreStore.perform(
异步:{(事务)->workutentity?在
让训练=事务。编辑(toWorkout)!
肌肉群中的肌肉{
让editedMuscle=transaction.edit(muscle)!
锻炼。肌肉?插入(编辑肌肉)
}
回程训练
},
成功:{(transactionWorkout)在//这里我们有transactionWorkout的肌肉
guard let unwrappedTransactionWorkout=transactionWorkout else{
返回
}
let workout=CoreStore.fetchExisting(unwrappedTransactionWorkout)//没有肌肉对象
让卫兵展开训练=其他训练{
返回
}
完成(.data(unwrappedWorkout))
},
失败:{(错误)在中
完成(.error(StackedError.internalFetchingDataError(消息:error.debugDescription)))
})
}
但正如我看到的,我在执行异步块时插入了肌肉,但当我插入时,并没有在异步块中添加任何肌肉

编辑:

当我发现workout.muscles中缺少反向关系时,现在我添加了它,看起来CoreStore更新训练实体是正确的

但现在,如果我调用函数几次,我会遇到另一个问题:

  • 第一个电话
  • AddMuscleGroup([1,2,3,4,5]…) 打印(展开工作。肌肉) [1,2,3,4,5]

  • 第二个调用addMuscleGroup([1,2,3,4,5,6,7]…)

    打印(展开工作。肌肉) [6,7]

  • (为了简化示例,我使用了1、2、3、4、5、6、7个数字),但实际上存在musclenty对象

    因此,由于第二次调用addMuscleGroups函数unwrappedWorkout.muscle有两个肌肉对象,而不是7个

    我添加了短视频:


    我也在回答了你的问题

    这是
    NSManagedObject
    s对于许多属性的一般行为

    首先,正如您所发现的,反向关系很重要

    其次,对于无序的
    @NSManaged
    属性,不建议使用
    Set
    。建议改用
    NSSet
    。 在该注释中,to-many关系被视为不可变的,这意味着您不能将对象直接插入到
    NSSet
    值中。有两种方法可以插入值

  • 直接分配新的
    NSSet
  • var muscles=(锻炼。肌肉是否设置?)??[]
    肌肉。插入(新肌肉)
    锻炼。肌肉=肌肉作为NSSet
    
  • 使用KVO可变访问器(为您创建
    NSMutableSet
    代理):
  • workout.mutableSetValueForKey(#关键路径(workutentity.muscles))
    .addObject(新肌肉)
    
    我有
    播放列表实体
    ,这就是我导入的样子。当我执行
    事务时会调用此函数。importUniqueObject
    对于我的播放列表,我想在这里做的是导入播放列表和关系(在这个简单的示例中称为
    歌曲
    )所需的所有属性:

    现在,您的本地存储在播放列表中有3首歌曲。但是我们需要等待服务器的响应

    因此,每次在服务器上添加歌曲并得到服务器回复时,我都会使用上面的
    update
    func重新导入播放列表

    服务器的第一个响应将只返回阵列中的一首歌曲,但正如我提到的,我的本地存储已经有3首歌曲,但此代码
    self.day=NSSet(array:days)
    将用一首歌曲替换3首歌曲

    第二个响应将返回[song1,song2],此代码
    self.day=NSSet(数组:days)
    将用2首歌曲替换3首歌曲

    当然,如果您有快速连接,并且服务器上的所有3个请求都立即完成,您可能不会看到这种效果,尽管我想使用@JohnEstropia建议的第二种方法:

    self.mutableSetValue(forKey: #keyPath(Playlist.songs))
                            .add(song)
    

    由于您的锻炼。肌肉关系被宣布为可选。。。在执行insert(editedMuscle)thnnks之前,您是否检查过它是否为nil!是的,它不是零,我看到如果我们在xcdatamodeld中对一些关系没有反转,CoreStore希望它正确映射。例如,在我的例子中,
    锻炼。肌肉
    关系与
    锻炼
    没有相反的关系。所以我通过增加逆解来解决这个问题,现在它起作用了。但是我有另一个问题我更新了我的问题在插入之前我们需要检查现有的吗?正如您所见,我使用了Swift集而不是NSSet,我认为NSSet可能会被完全覆盖。我在这里添加了调用函数的视频(我在上面指定了该视频):我将Swift.Set更改为@NSManaged属性的NSSet,现在您的代码对我有效,谢谢!有一件事我注意到,一些人建议使用这种方式:“默认情况下,泛型会生成许多关系,比如NSSet?。但是现在谁能处理无类型的容器呢?请使用本机Swift Set类型:”不管怎样,我还是从这个链接切换到了NSSet和所有工作。很久以前,Xcode实际上为无序关系生成了
    Set
    ,但他们发现,正如您所观察到的,由于核心数据使用的具体
    NSSet
    子类的动态行为,它打破了快速桥接。因此,他们将其恢复为
    NSSet
    。我忘了苹果在哪里记录了这种行为,但我想这是在过去的一个Xcode发行说明中。我已经发布了答案,希望这有一天能帮助到别人。只是想让你看看。所以我用了你的答案,它很完美,但是这个
    锻炼.muscles=肌肉作为NSSet
    在某些情况下非常棘手,我在答案中强调了它们。
    inserNewSong(song1, toPlaylistWithId: someId_abc1)
    inserNewSong(song2 toPlaylistWithId: someId_abc1)
    inserNewSong(song3 toPlaylistWithId: someId_abc1)
    
    self.mutableSetValue(forKey: #keyPath(Playlist.songs))
                            .add(song)