rickclephas / KMP-ObservableViewModel

Library to use AndroidX/Kotlin ViewModels with SwiftUI
MIT License
583 stars 27 forks source link

Cannot find type 'Kmm_viewmodel_coreKMMViewModel' in scope #10

Closed laisuki1109 closed 1 year ago

laisuki1109 commented 1 year ago

Environment: I defined the viewModel in shared module and exported the module to xcframework and imported to other ios app project. It is work without calling any function in viewModel. Then I added packages of KMMViewModel and also the KMM Native Coroutines.

However when I follow the readme that create the file KMMViewModel.swift

import KMMViewModelCore
import shared

extension Kmm_viewmodel_coreKMMViewModel: KMMViewModel { }

It cause Cannot find type 'Kmm_viewmodel_coreKMMViewModel' in scope. How to solve this?

rickclephas commented 1 year ago

The name or the KMM_viewmodel_coreKMMViewModel class is generated by the Kotlin compiler, depending on your setup it might be a little different. However it should always end with KMMViewModel. Could you try and see what Xcode autocomple suggests if you type KMMViewModel?

laisuki1109 commented 1 year ago

The name or the KMM_viewmodel_coreKMMViewModel class is generated by the Kotlin compiler, depending on your setup it might be a little different. However it should always end with KMMViewModel. Could you try and see what Xcode autocomple suggests if you type KMMViewModel?

After I tried reimport the share framework, it works! However I have a question to ask,


class RegistrationViewModel: KMMViewModel() {
    private val scope = CoroutineScope(Dispatchers.Default + Job())

    sealed class Input {
        data class Fetch(val id: String): Input()
    }

    private val repo = TestRepository()
    private val _input = MutableSharedFlow<Input>()
    private val _characterDetail = _input.filterIsInstance<Input.Fetch>()
        .map { repo.getCharacter(it.id) }
        .map { it?.name }

    @NativeCoroutinesState
    val characterDetail = _characterDetail.stateIn(viewModelScope.coroutineScope, SharingStarted.WhileSubscribed(), null)

    fun getRacer(): StateFlow<List<Racer>> {
        return flow {
            emit(Racer.getRacerList())
        }.stateIn(scope, SharingStarted.Lazily, emptyList())
    }

    fun getCharacterDetail() {
        viewModelScope.coroutineScope.launch {
            _input.emit(Input.Fetch("1"))
        }
    }

}

My SwiftUI view

import SwiftUI
import shared
import KMMViewModelSwiftUI

struct ContentView: View {
    @StateViewModel var viewModel = RegistrationViewModel()
    var body: some View {
        var detail = viewModel.characterDetail

        var greeting = Racer.Companion().getRacerList()
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)

            Text(greeting.first?.name ?? "lulu")
            Text(detail ?? "detail")
            Button(action: { viewModel.getCharacterDetail() }) {
                Text("GET!")
            }
        }
        .padding()
    }
}

This is my viewModel, and I am trying to get the characterDetail in SwiftUI view, but the characterDetail cannot be update after click the button, the characterDetail can be observed the value in android.

If I want to call in ios app, what updates or do I need to change the SharedFlow to Stateflow?

rickclephas commented 1 year ago

Alright, good to hear! Regarding your question, in order for the changes to propagate to Swift you'll need to use the KMMViewModel overloads of the stateIn function:

import com.rickclephas.kmm.viewmodel.stateIn

It accepts the viewModelScope as the first parameter.

laisuki1109 commented 1 year ago

OK, get it 👍🏻 Thank you very much