Realm 文档介绍,同一个 Realm 实例,可以被任意线程访问,即能够在任意线程进行写操作,写事务被包裹在 beginWrite
和 commitWrite
之间。不过在开始写事务到结束之前,只能由单一的线程访问 RealmObject 对象,否则会抛出跨线程访问异常。
在项目中遇到一个需求是,在写事务中读取数据对象之后,需要做一个异步操作,完成之后更新对象的状态。例如,上传本地数据失败重传处理,需要先读取同步失败的对象,再重传,成功后更新同步状态。
为了便于管理, Realm 的写事务可以用同一个串行队列,以闭包的形式将写事务(Task)异步分发(Dispatch)执行。上述需求需要嵌套的使用写事务来完成,伪代码请见配图。
然而,执行程序挂在 58 行,从线程堆栈看, 内部实际挂在Realm verify_thread();
方法。原因是内层写操作被异步分发到另一个线程了,导致跨线程访问奔溃。
能想到的解决方法是,copy results 里面的每个 RealmObject 对象,放入新的数组,供另一个线程访问并更新。
这个问题的根本原因在于,没有意识到异步分发任务到同一个串行队列,并不能保证任务都在同一个线程上执行。虽然在学习队列使用的时候,有看过需要注意这一点,但是在实际使用中,还是被忽视了。