Realm新迁移在新安装应用二次启动时异常触发问题咨询
从你的描述和代码来看,问题出在Realm配置的错误设置方式以及迁移逻辑的不完整性上,具体原因和解决方法如下:
核心问题根源
1. 重复覆盖默认配置导致迁移逻辑丢失
你在didFinishLaunchingWithOptions中三次赋值Realm.Configuration.defaultConfiguration,每次赋值都会完全覆盖之前的配置。这意味着最终生效的只有最后一次设置的schemaVersion 3和对应的迁移块,而迁移1、迁移2的逻辑完全丢失了。更关键的是,当新安装应用时,如果有代码提前初始化了Realm(比如全局单例),会导致数据库以默认的schemaVersion 0创建,而你的迁移3代码并没有处理从0直接升级到3的场景,从而在二次启动触发迁移时崩溃。
2. 首次启动时Realm可能提前初始化
如果你的应用中存在全局单例、静态属性等在AppDelegate完成配置之前就打开Realm的情况,Realm会使用默认配置(schemaVersion 0)创建数据库。此时用户首次启动添加的数据会写入这个schemaVersion 0的库中。二次启动时,AppDelegate设置了schemaVersion 3的配置,Realm检测到版本差异触发迁移,但你的迁移逻辑没有处理oldSchemaVersion < 3的所有情况(比如从0到3),导致访问不存在的旧模型属性,抛出NSException。
3. 场景3正常的原因
新安装后不立即添加数据,杀死进程再重启时,AppDelegate的配置已经完全设置完成,Realm会直接以schemaVersion 3创建数据库,后续启动版本匹配,不会触发迁移,因此运行正常。
解决方案
1. 合并所有迁移逻辑到单一配置
不要多次覆盖默认配置,应该创建一个包含所有版本迁移逻辑的单一Configuration实例,设置最新的schemaVersion:
class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Realm.Configuration.defaultConfiguration = Realm.Configuration( schemaVersion: 3, migrationBlock: { migration, oldSchemaVersion in // 处理从版本0到1的迁移 if oldSchemaVersion < 1 { // migration 1的配置逻辑 } // 处理从版本1到2的迁移 if oldSchemaVersion < 2 { // migration 2的配置逻辑 } // 处理从版本2到3的迁移 if oldSchemaVersion < 3 { // migration 3的配置逻辑 } } ) // 确保在这里之后再初始化Realm相关操作 return true } }
2. 确保Realm初始化时机晚于配置设置
检查应用中所有访问Realm的代码,比如全局单例、ViewModel初始化等,确保它们在AppDelegate完成默认配置设置之后才执行。例如,将单例的Realm初始化改为延迟加载:
class RealmManager { static let shared = RealmManager() private var _realm: Realm? var realm: Realm { if let realm = _realm { return realm } do { let realm = try Realm() _realm = realm return realm } catch { fatalError("Failed to initialize Realm: \(error)") } } }
3. 完善迁移逻辑的边界处理
在迁移块中,确保每个版本的迁移逻辑都能独立处理,不要假设旧版本只能是前一个版本。比如,迁移3的逻辑要考虑oldSchemaVersion可能是0、1或2的情况,避免访问不存在的旧属性。
验证步骤
- 卸载应用,清除所有缓存
- 使用修正后的代码重新编译安装
- 首次启动直接添加数据,二次启动检查是否崩溃
- 测试从旧版本(比如schemaVersion 2)升级到3的场景,确保迁移正常
内容的提问来源于stack exchange,提问作者fs_tigre

