Solved: mutation attempt of frozen kotlin.native.internal.Ref@xxxxxxx
Problem
Problem
I encountered the following error recently. I am using the realm module in the KMM module, and in one of the methods, it reports errors like below on the iOS side, but on Android emulator, it works correctly.
It is considered unexpected and unhandled instead. Program will be terminated.
Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.native.internal.Ref@1b612a8
at 0 iosApp 0x102ff89d8 kfun:kotlin.Throwable#<init>(kotlin.String?){} + 88
at 1 iosApp 0x102ff31c6 kfun:kotlin.Exception#<init>(kotlin.String?){} + 86
at 2 iosApp 0x102ff33b6 kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 86
at 3 iosApp 0x103006d96 kfun:kotlin.native.concurrent.InvalidMutabilityException#<init>(kotlin.String){} + 86
...
After investigate the code, I find the problem is I change the variable value inside writeBlock, the code will throw error is like below:
override fun addItem(prefix: String) {
var count = 0
realm.writeBlocking {
for (i in 1..10) {
val itemCount = query(Item::class).count().find()
val item = copyToRealm(Item().apply {
index = itemCount + 1
thread = prefix
isComplete = false
})
count++ // This code will throw exception on iOS
println("Added item ${item.index}")
}
}
println("The count is $count")
}
After I changed the code like the following, it works correctly.
override fun addItem(prefix: String) {
var count = 0
for (i in 1..10) {
realm.writeBlocking {
val itemCount = query(Item::class).count().find()
val item = copyToRealm(Item().apply {
index = itemCount + 1
thread = prefix
isComplete = false
})
println("Added item ${item.index}")
}
count++ // Update the variable outside the writeBlocking works fine
}
println("The count is $count")
}
Solution
In order to solve the problem, we should avoid updating the variable inside the writeBlocking
, or change the variable outside the writeBlocking
.
Thanks for your reading and happy thanksgiving day!