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

如何获取Realm对象修改前的取值?Objective-C/Swift开发咨询

我完全懂你的痛点——Core Data里NSManagedObjectContextWillSaveNotification那种能在保存前抓旧值的能力,放到Realm里确实没直接对应的API,毕竟Realm的观察者默认都是提交变更后才触发的。不过别担心,有几个实用的方案可以模拟这个需求,不管用Swift还是Objective-C都能搞定:

方案1:手动记录旧值(最简单直接)

如果只是单个对象或少量属性修改,最直接的方式就是在开启写事务前,先把要修改的属性值存到临时变量里。

Swift 示例

import RealmSwift

class Task: Object {
    @Persisted var title: String
}

// 使用流程
let realm = try! Realm()
guard let task = realm.objects(Task.self).first else { return }

// 修改前先留存旧值
let oldTitle = task.title

try! realm.write {
    task.title = "完成周报"
}

// 这里就能对比新旧值了
print("修改前标题:\(oldTitle),修改后标题:\(task.title)")

Objective-C 示例

#import <Realm/Realm.h>

@interface Task : RLMObject
@property NSString *title;
@end

@implementation Task
@end

// 使用流程
RLMRealm *realm = [RLMRealm defaultRealm];
Task *task = [Task allObjectsInRealm:realm].firstObject;

// 留存旧值
NSString *oldTitle = task.title;

[realm transactionWithBlock:^{
    task.title = @"完成周报";
}];

NSLog(@"修改前标题:%@,修改后标题:%@", oldTitle, task.title);

这个方案的优势是零额外依赖,适合场景单一的简单修改操作。

方案2:利用Realm快照(适合批量修改)

如果要处理多个对象或批量属性修改,手动记录太繁琐,可以用Realm的**快照(Freeze)**功能——在写事务前给对象创建一个不可变的快照,它会保留对象当前的状态,哪怕原对象被修改,快照里的旧值依然有效。

Swift 示例

let realm = try! Realm()
guard let task = realm.objects(Task.self).first else { return }

// 创建对象快照
let taskSnapshot = task.freeze()

try! realm.write {
    task.title = "更新后的任务标题"
}

// 对比快照和修改后的对象
print("旧标题:\(taskSnapshot.title),新标题:\(task.title)")

Objective-C 示例

RLMRealm *realm = [RLMRealm defaultRealm];
Task *task = [Task allObjectsInRealm:realm].firstObject;

// 创建快照
Task *taskSnapshot = [task freeze];

[realm transactionWithBlock:^{
    task.title = @"更新后的任务标题";
}];

NSLog(@"旧标题:%@,新标题:%@", taskSnapshot.title, task.title);

注意:快照功能是Realm 10.0+版本才支持的,如果你的项目用了更低版本,可以用objectInRealm:方法创建对象副本替代,只是效率会稍低一些。

方案3:自定义“即将保存”通知(模拟Core Data全局监听)

如果你想要类似Core Data那种全局通知的效果,能统一处理所有对象的保存前逻辑,可以自己封装写事务的工具类,在事务开启前触发自定义通知,把旧值快照传递出去。

Swift 示例

// 定义自定义通知名
extension Notification.Name {
    static let realmContextWillSave = Notification.Name("RealmContextWillSave")
}

// 封装写事务方法
func realmWrite(with objects: [Object], block: () throws -> Void) throws {
    // 收集所有对象的旧值快照
    let snapshots = objects.map { $0.freeze() }
    
    // 发送即将保存的通知
    NotificationCenter.default.post(
        name: .realmContextWillSave,
        object: nil,
        userInfo: ["oldSnapshots": snapshots]
    )
    
    // 执行写事务
    let realm = try! Realm()
    try realm.write(block)
}

// 使用方式
let task = realm.objects(Task.self).first!
try! realmWrite(with: [task]) {
    task.title = "新任务标题"
}

// 监听自定义通知
NotificationCenter.default.addObserver(
    forName: .realmContextWillSave,
    object: nil,
    queue: .main
) { notification in
    if let snapshots = notification.userInfo?["oldSnapshots"] as? [Task] {
        snapshots.forEach { snapshot in
            print("即将保存,旧标题:\(snapshot.title)")
        }
    }
}

Objective-C 示例

// 定义通知名
static NSString *const RealmContextWillSaveNotification = @"RealmContextWillSaveNotification";

// 封装事务方法
- (void)realmWriteWithObjects:(NSArray<RLMObject *> *)objects block:(void (^)(void))block {
    NSMutableArray *snapshots = [NSMutableArray array];
    for (RLMObject *obj in objects) {
        [snapshots addObject:[obj freeze]];
    }
    
    // 发送通知
    [[NSNotificationCenter defaultCenter] postNotificationName:RealmContextWillSaveNotification
                                                        object:nil
                                                      userInfo:@{@"oldSnapshots": snapshots}];
    
    // 执行事务
    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm transactionWithBlock:block];
}

// 使用方式
Task *task = [Task allObjectsInRealm:[RLMRealm defaultRealm]].firstObject;
[self realmWriteWithObjects:@[task] block:^{
    task.title = @"新任务标题";
}];

// 监听通知
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleWillSaveNotification:)
                                             name:RealmContextWillSaveNotification
                                           object:nil];

- (void)handleWillSaveNotification:(NSNotification *)notification {
    NSArray<Task *> *snapshots = notification.userInfo[@"oldSnapshots"];
    for (Task *snapshot in snapshots) {
        NSLog(@"即将保存,旧标题:%@", snapshot.title);
    }
}

关键注意点

  • Realm的写事务是原子性的,事务内修改对象后,原对象的值会立刻更新,所以必须在事务开始前记录旧值或创建快照。
  • 如果是大量对象的批量操作,优先选择快照或自定义通知方案,避免手动记录每个属性的冗余代码。

内容的提问来源于stack exchange,提问作者Hua-Ying

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:38:17