You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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
    }
}

问题原因与解决方案

核心原因

  1. 枚举原始类型不匹配:CoreData中的Difficulty枚举使用Int64作为原始类型,而SwiftData版本改为了Int。SQLite中CoreData存储的是64位整数,SwiftData尝试用32位整数解析,导致类型不兼容,无法读取原有数据,最终字段被置空。
  2. 自动迁移不处理枚举类型变更:SwiftData的自动迁移不会自动适配枚举原始类型的差异,必须保证两端的枚举定义完全一致。

修复步骤

  1. 统一枚举原始类型:将SwiftData中的Difficulty枚举原始类型改为Int64,与CoreData版本保持一致。
  2. 显式指定存储策略(可选但推荐):在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:31:20