CoreData解码NSManagedObject崩溃:无法保存跨存储引用对象
解码NSManagedObject时的跨存储引用崩溃排查与解决
崩溃原因分析
从崩溃日志和代码可以定位到核心问题:
- 部分
Exercise对象是临时对象(从其Core Data URL格式x-coredata:///Exercise/tXXX可以看出,缺少存储唯一标识段),但被关联到了已经完成持久化的FitnessWrapper对象上。 - 代码中在
FitnessWrapper初始化完成后立即调用了saveContext(),导致FitnessWrapper提前获得永久存储ID;后续创建的Exercise还是临时状态(未被持久化),此时将临时对象关联到已持久化对象,保存时Core Data会判定为跨存储引用,触发Cannot save objects with references outside of their own stores错误。
解决方法
1. 移除提前保存操作,统一完成所有关联后再保存
修改FitnessWrapper的解码初始化方法,删除创建后的提前保存,只在所有Exercise关联完成后执行一次保存:
required convenience public init(from decoder: any Decoder) throws { guard let entity = NSEntityDescription.entity(forEntityName: String(describing: FitnessWrapper.self), in: PersistenceController.shared.container.viewContext) else { fatalError("Exercise Instantiation failed") } let shared = PersistenceController.shared let context = shared.container.viewContext self.init(entity: entity, insertInto: context) let values = try decoder.container(keyedBy: CodingKeys.self) // 移除提前保存的代码 print("59") if let allExercisesLcl = try values.decodeIfPresent([ExerciseDTO].self, forKey: .InCompletedExercises) { for exerciseDTO in allExercisesLcl { let exercise = exerciseDTO.toExercise(in: context) exercise.date = oldStaticDate exercise.type = ExerciseType.NCB.rawValue UserDefaultsManager.shared.dummyFitnessIncorporated = true self.addToAllExercises(exercise) exercise.fitnessWrapper = self } } print("68") CoreDataManager.shared.saveContext() }
2. 确保上下文操作的原子性
当前saveContext方法已使用performAndWait保证线程安全,需确保所有关联对象的创建、关联操作都在同一个上下文的操作周期内完成,避免部分对象提前持久化。
3. 排查其他临时对象关联场景
检查代码中是否存在其他将未持久化Exercise关联到已持久化FitnessWrapper的场景,比如从其他上下文获取的对象、未插入当前上下文的对象,确保所有关联对象都属于同一个存储上下文。
内容的提问来源于stack exchange,提问作者Aaban Tariq Murtaza
相关产品推荐
相关产品推荐

