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

从Obj-C Realm迁移至RealmSwift:如何动态迁移属性避免硬编码?

动态迁移方案(从Objective-C Realm到RealmSwift)

核心思路:通过Schema元数据自动映射属性

不需要硬编码每个属性,可借助旧对象的Schema元数据遍历所有属性,自动完成值的复制,同时单独处理主键、数据类型变更这类特殊场景。

基础动态迁移代码

migrationBlock: { migration, oldSchemaVersion in
    if oldSchemaVersion < 1 {
        migration.enumerateObjects(ofType: Countries.className()) { oldObject, newObject in
            guard let oldObj = oldObject, let newObj = newObject else { return }
            
            // 遍历旧对象的所有属性
            for property in oldObj.schema.properties {
                let propertyName = property.name
                
                // 跳过不需要迁移的属性(按需添加)
                if propertyName == "OldUnusedProperty" {
                    continue
                }
                
                // 处理数据类型变更的特殊情况
                if propertyName == "NeedConvertProperty" {
                    // 示例:NSNumber转Swift Int
                    if let oldValue = oldObj[propertyName] as? NSNumber {
                        newObj[propertyName] = oldValue.intValue
                    }
                    continue
                }
                
                // 普通属性直接复制
                newObj[propertyName] = oldObj[propertyName]
            }
            
            // 单独处理主键映射(如果新旧模型主键字段/类型不同)
            // 示例:新模型主键为countryCode,旧模型对应值在Country_Code字段
            // newObj["countryCode"] = oldObj["Country_Code"]
        }
    }
}

关键注意事项

  • 主键处理:主键是模型核心标识,若新旧模型的主键字段名或类型不一致,必须手动映射,无法完全自动化。
  • 数据类型兼容:基础类型(如NSString↔String、NSNumber↔Int)Realm会自动兼容,但自定义类型、NSDecimalNumber转Decimal这类特殊场景需手动转换。
  • 嵌套对象迁移:嵌套对象可递归遍历其Schema属性,同样实现动态迁移,避免硬编码嵌套字段。
  • 属性过滤:新模型删除的旧属性,需在遍历中跳过,避免无效赋值。

通用迁移扩展(可选)

可封装通用方法减少重复代码:

extension Migration {
    func migrateObject(oldObject: Object, newObject: Object, excludeProperties: [String] = [], typeConverters: [String: (Any?) -> Any?] = [:]) {
        for property in oldObject.schema.properties {
            let name = property.name
            guard !excludeProperties.contains(name) else { continue }
            
            if let converter = typeConverters[name] {
                newObject[name] = converter(oldObject[name])
            } else {
                newObject[name] = oldObject[name]
            }
        }
    }
}

// 使用示例
migrationBlock: { migration, oldSchemaVersion in
    if oldSchemaVersion < 1 {
        migration.enumerateObjects(ofType: Countries.className()) { oldObj, newObj in
            guard let o = oldObj, let n = newObj else { return }
            
            // 定义需要类型转换的属性
            let typeConverters: [String: (Any?) -> Any?] = [
                "Population": { value in
                    (value as? NSNumber)?.intValue
                }
            ]
            
            // 执行通用迁移
            migration.migrateObject(oldObject: o, newObject: n, excludeProperties: ["OldUnusedProp"], typeConverters: typeConverters)
            
            // 主键单独映射
            n["countryCode"] = o["Country_Code"]
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:33:21