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

SwiftData自定义迁移仅在iPad生效,iPhone及模拟器被跳过问题排查

SwiftData自定义迁移仅在iPad触发,iPhone/模拟器跳过的问题

问题描述

为包含自定义枚举和结构体(复合属性)的SwiftData数据模型执行自定义迁移,新版本新增若干枚举。但迁移仅在iPad上成功执行,iPhone及模拟器中被跳过——即便从Xcode或TestFlight安装的是同一版本。迁移被跳过时,新增枚举未完成初始化(尽管已设置默认值),触发如下错误:

CoreData: warning: validation recovery attempt FAILED with Error Domain=NSCocoaErrorDomain Code=1560 "Multiple validation errors occurred." UserInfo={NSDetailedErrors=(
"Error Domain=NSCocoaErrorDomain Code=1570 "%{PROPERTY}@ is a required value."

已完成的排查:

  • 确认DataModels的versionChecksums中V1版本校验码始终一致;
  • 通过断点验证MigrationPlan在所有设备及模拟器中均已加载,但仅在iPad上运行;
  • 测试环境为iOS17.4和17.5。

相关代码片段

MigrationPlan

enum DataMigrationPlan: SchemaMigrationPlan {
    
    static var schemas: [any VersionedSchema.Type] {
        [DataSchemaV1.self, DataSchemaV2.self]
    }
        
    static let migrateV1toV2 = MigrationStage.custom(
        fromVersion: DataSchemaV1.self,
        toVersion: DataSchemaV2.self,
        willMigrate: { context in
            print("will migrate")
        }, didMigrate: { context in
            print("did migrate")
            // … setting values for new properties
        }
    )
    
    static var stages: [MigrationStage] {
        [migrateV1toV2]
    }
}

ModelContainer

let modelConfiguration = ModelConfiguration(isStoredInMemoryOnly: false)
sharedModelContainer = try ModelContainer (
    for: DataSchemaV2.FilterGroup.self,
    migrationPlan: DataMigrationPlan.self,
    configurations: modelConfiguration
)

DataSchemaV1

enum DataSchemaV1: VersionedSchema {
    static var versionIdentifier = Schema.Version(1, 0, 0)
    
    static var models: [any PersistentModel.Type] {
        [DataSchemaV1.FilterGroup.self]
    }

    @Model
    final class FilterGroup: Identifiable {
        public let id: String = UUID().uuidString
        var timestamp: Date = Date.now

        var theme: WidgetTheme = WidgetTheme.calendar // string enum
        var myStruct: [MyStruct] = []
    }

    static var sampleData: FilterGroup {
        return FilterGroup(...)
    }

    struct MyStruct: Codable, Identifiable {
        var id: UUID = UUID()
        var someEnum: SomeEnum = SomeEnum.something
        ...
    }
}

DataSchemaV2

enum DataSchemaV2: VersionedSchema {
    static var versionIdentifier = Schema.Version(2, 0, 0)
    
    static var models: [any PersistentModel.Type] {
        [DataSchemaV2.FilterGroup.self]
    }

    @Model
    final class FilterGroup: Identifiable {
        // ... same as v1
        var newlyAddedEnum: NewEnum = NewEnum.something
    }

    // ...
}

原因分析及解决方案

可能原因

  1. 自动迁移判定差异:CoreData在iPhone/模拟器上可能判定当前schema与持久化存储的schema兼容,跳过自定义迁移直接尝试自动迁移,但自动迁移无法正确处理自定义枚举的默认值初始化,导致校验失败。
  2. 设备特定缓存:iOS17.x的SwiftData在不同设备上存在schema校验缓存差异,导致iPhone/模拟器未正确识别schema版本变化,跳过迁移流程。

解决方案

  1. 禁用自动迁移,强制自定义迁移
    在ModelConfiguration中明确关闭自动迁移,确保自定义迁移计划被强制执行:

    let modelConfiguration = ModelConfiguration(
        isStoredInMemoryOnly: false,
        automaticMigrationsEnabled: false
    )
    sharedModelContainer = try ModelContainer (
        for: DataSchemaV2.FilterGroup.self,
        migrationPlan: DataMigrationPlan.self,
        configurations: modelConfiguration
    )
    
  2. 确保枚举类型的CoreData兼容性
    检查新增的NewEnum是否正确遵循Codable和PersistentEnum(SwiftData专属枚举协议),并确保原始类型与CoreData存储兼容:

    enum NewEnum: String, Codable, PersistentEnum {
        case something
        // 其他枚举值
    }
    
  3. 在自定义迁移中显式设置枚举值
    即便属性有默认值,也在didMigrate闭包中为所有现有实体显式设置新增枚举值,避免自动初始化失败:

    didMigrate: { context in
        print("did migrate")
        do {
            let filterGroups = try context.fetch(FetchDescriptor<DataSchemaV2.FilterGroup>())
            for group in filterGroups {
                group.newlyAddedEnum = NewEnum.something
            }
            try context.save()
        } catch {
            print("Migration save failed: \(error)")
        }
    }
    
  4. 清理设备缓存
    模拟器侧:彻底删除App并重置模拟器;iPhone侧:删除App后重启设备,清除可能存在的schema缓存。

内容的提问来源于stack exchange,提问作者ARS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:32:34