Solved: mutation attempt of frozen kotlin.native.internal.Ref@xxxxxxx

Problem

Solved: mutation attempt of frozen kotlin.native.internal.Ref@xxxxxxx

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!