最近几个项目都用的 Realm
数据库, 虽然用起来特别方便但是坑也是特别多.
最近一个项目遇到一个情况, 在删除对象之后就会导致程序崩溃: Object has been deleted or invalidated when delete object
.
Google 找到的方法都试了一遍也不行, 不知道是不是这个版本的 BUG. 项目紧急暂时未找出原因. 最后找到了一个曲线救国的方法.
问题代码
注册通知, 在 RLMResults
的内容发生变化的时候刷新数据.
1
2
3
4
5
6
// 注册通知, 刷新数据
__weak typeof(self) ws = self;
self.dataToken = [_serviceGroups addNotificationBlock:^(RLMResults<ServiceGroupModel *> * _Nullable results, RLMCollectionChange * _Nullable change, NSError * _Nullable error) {
ws.serviceGroups = results;
[ws.outlineView reloadData];
}];
删除对象部分的代码:
1
2
3
4
5
// 删除对象
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm deleteObject:obj];
}];
这样会直接造成 Crash. 原因就是对象原本已经被删除无效了, 但是什么地方的代码逻辑还是尝试对该对象进行操作. 然后被 Realm
的机制终止掉了.
虽然已经确保没有任何对对象的引用, 但是问题无法得到解决.
各种调试之后可以确认此时在我的代码部分已经完全没有对该对象的引用了.
曲线救国
给每个对象添加一个 isDelete
的 BOOL
属性来对对象做 标记删除 使用.
1
2
// 查询部分要添加条件, 筛选掉被标记删除的对象
self.serviceGroups = [ServiceGroupModel objectsWhere:@"isDelete = false"];
我把删除操作分为二步:
- 先对数据进行标记删除, 清除所有逻辑对被删除对象的引用.
- 再真正的从数据库删除对象.
1
2
3
4
5
6
7
8
9
10
// 先把对象改为标记删除
RLMRealm *realm = [RLMRealm defaultRealm];
[[RLMRealm defaultRealm] transactionWithBlock:^{
obj.isDelete = YES;
}];
// 再做真正的删除
[realm transactionWithBlock:^{
[realm deleteObjects:[ServiceGroupModel objectsWhere:@"isDelete = true"]];
}];
这样暂时是把问题解决了. 但是却并不完美.
以后找到了原因再来补充.