将CoreData枚举迁移至SwiftData时数据丢失崩溃的解决方法
问题:CoreData迁移至SwiftData时枚举字段丢失数据并引发崩溃
将包含枚举的CoreData对象迁移到SwiftData时,自动迁移未正常工作,出现数据丢失和应用崩溃的情况。复现步骤:
- 运行CoreData版本的应用
- 添加若干条目
- 查看sqlite文件确认数据存在
- 运行SwiftData版本的应用
此时应用状态异常,sqlite文件中的difficulty列变为空。
CoreData 相关代码
@objc public class Item : NSManagedObject, Identifiable { @NSManaged public var difficulty: Difficulty @NSManaged public var timestamp: Date } @objc public enum Difficulty: Int64, Codable, CaseIterable, Identifiable{ case easy case medium case hard case expert var title: String{ switch self { case .easy: return "Easy" case .medium: return "Medium" case .hard: return "Hard" case .expert: return "Expert" } } public var id: String{ title } }
SwiftData 相关代码
@Model public class Item{ public var difficulty: Difficulty public var timestamp: Date init(difficulty: Difficulty, timestamp: Date) { self.difficulty = difficulty self.timestamp = timestamp } } public enum Difficulty: Int, Codable, CaseIterable, Identifiable { case easy case medium case hard case expert var title: String{ switch self { case .easy: return "Easy" case .medium: return "Medium" case .hard: return "Hard" case .expert: return "Expert" } } public var id: String{ title } }
问题原因与解决方案
核心原因
- 枚举原始类型不匹配:CoreData中的
Difficulty枚举使用Int64作为原始类型,而SwiftData版本改为了Int。SQLite中CoreData存储的是64位整数,SwiftData尝试用32位整数解析,导致类型不兼容,无法读取原有数据,最终字段被置空。 - 自动迁移不处理枚举类型变更:SwiftData的自动迁移不会自动适配枚举原始类型的差异,必须保证两端的枚举定义完全一致。
修复步骤
- 统一枚举原始类型:将SwiftData中的
Difficulty枚举原始类型改为Int64,与CoreData版本保持一致。 - 显式指定存储策略(可选但推荐):在SwiftData的
Item类中,给枚举字段添加@Attribute注解,明确指定存储为64位整数,消除迁移时的类型歧义。
修正后的SwiftData代码
@Model public class Item{ @Attribute(.integer64) // 显式指定存储类型为64位整数,匹配CoreData public var difficulty: Difficulty public var timestamp: Date init(difficulty: Difficulty, timestamp: Date) { self.difficulty = difficulty self.timestamp = timestamp } } public enum Difficulty: Int64, Codable, CaseIterable, Identifiable { // 改为Int64类型 case easy case medium case hard case expert var title: String{ switch self { case .easy: return "Easy" case .medium: return "Medium" case .hard: return "Hard" case .expert: return "Expert" } } public var id: String{ title } }
额外注意事项
- 若已出现数据丢失,需先恢复CoreData版本的sqlite数据,再应用修复后的代码重新执行迁移。
- 后续模型变更时,需保证CoreData与SwiftData的字段类型、枚举定义完全对齐,避免自动迁移失败。
内容的提问来源于stack exchange,提问作者Richard Witherspoon
相关产品推荐
相关产品推荐

