icerockdev / moko-mvvm

Model-View-ViewModel architecture components for mobile (android & ios) Kotlin Multiplatform development
https://moko.icerock.dev/
Apache License 2.0
1k stars 95 forks source link

Crashes in iOS when using Moko's LiveData in callbacks descending to Sqldelight listeners. #35

Open caesar84mx opened 4 years ago

caesar84mx commented 4 years ago

CommonDatabase.kt:

fun observe(id: Int, callback: (List<BlablaEntity>) -> Unit) {
        if (id in observers.keys) {
            throw RuntimeException("Already observing id $id")
        } else {
            val listener = object : Query.Listener {
                override fun queryResultsChanged() {
                    callback(
                        database
                            .databaseQueries
                            .findAll { entityId: Long, name: String, blabla: String ->
                                BlablaEntity(
                                    id = entityId,
                                    name = name,
                                    blabla = blabla
                                )
                            }.executeAsList()
                    )
                }
            }

            observers[id] = listener
            database.databaseQueries.findAll().addListener(listener)
        }
    }

Repo.kt:

fun observe(id: Int, onChange: (List<BlablaEntity>) -> Unit) {
        CommonDatabase.observe(id, onChange)
    }

ViewModel.kt:

val statusLiveData: MutableLiveData<Status> = MutableLiveData(Status.Loading)
fun startObserving() {
        val subscriptionId = idCounter.incrementAndGet()
        repo.observe(subscriptionId) { data ->
                statusLiveData.postValue(Status.Success(data))
        }
    }

When using startObserving() method from iOS, the app crashes with the following:

Instances of kotlin.Error, kotlin.RuntimeException and subclasses aren't propagated from Kotlin to Objective-C/Swift. Other exceptions can be propagated as NSError if method has or inherits @Throws annotation. Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.Array@1ca1508

Alex009 commented 4 years ago

hi! Error show that something was freezed. i found that issue - https://github.com/cashapp/sqldelight/issues/1390#issuecomment-507914279

Adding a listener on native means it'll freeze the listener you pass in. Listeners in general on native absolutely work, with the caveat that the listener will get frozen when it's passed in (as well as anything it references).

LiveData implementation now not support concurrency calls, but later it should be added.

for now you can try use ThreadLocalRef as here - https://github.com/cashapp/sqldelight/issues/1390#issuecomment-513060205