https://kotlinlang.org logo
#koin
Title
# koin
m

Mobile Dev.

07/16/2022, 11:50 PM
Hello, i'm using koin with annotations in kmm project. In Android it's okay but in ios there is a problem i couldn't fix it. When i open a page in the application and call a view model class that I define as @single on that page. I use a mutable object from the View model and update it, then I close the page. When I open the page back, it continues to use whatever the latest state of the viewmodel class is. I want it to recreate the viewmodel every time the page is opened. It's happening only ios not android. Here is my common DI file
Copy code
fun appModule() = listOf(AppModule().module)

@Module
@ComponentScan("com.makswin.bifrost")
class AppModule

class DependencyInjection : KoinComponent {
    val listTrainingsViewModel: ListTrainingsViewModel by inject()
    val getLastTrainingViewModel: GetLastTrainingViewModel by inject()
    val addFeedbackViewModel: AddFeedbackViewModel by inject()
    val insuranceViewModel: InsuranceViewModel by inject()
    val authViewModel: AuthViewModel by inject()
}

fun initKoin() {
    startKoin {
        modules(appModule())
    }
}
My App Delegate on ios
Copy code
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    AppModuleKt.doInitKoin()
    return true
  }
Here is my observable view model object
Copy code
class ObservableListTrainingViewModel : ObservableObject {
  @Published var state: ListTrainingsState?
   
  var viewModel: ListTrainingsViewModel?
   
  init(viewModel: ListTrainingsViewModel) {
    self.viewModel = viewModel
    asPublisher(viewModel.state)
      .compactMap { $0 }
      .receive(on: DispatchQueue.main)
      .assign(to: &state)
  }
}
Here is my sample swift ui view
Copy code
struct ContentView : View {
   
  @Environment(\.presentationMode) var presentationMode
   
  @ObservedObject var viewModel: ObservableListTrainingViewModel

  init() {
    viewModel = ObservableListTrainingViewModel(viewModel: DependencyInjection().listTrainingsViewModel)
  }
   
  var body: some View {
     
      VStack {
        if let state = viewModel.state {
          Button("Button") {
            if state.trainings.isEmpty {
              self.viewModel.viewModel?.getTrainings(type: .next) // api call
            } else {
              presentationMode.wrappedValue.dismiss() // close the page
            }
          }
          if state.isLoading {
            Text("LOADING")
          }
          if !state.trainings.isEmpty {
            Text("\(state.trainings.first?.title ?? "NONE")")
          }
        }
      }
  }
}
and my Common View Model Class
Copy code
@Single
class ListTrainingsViewModel(val listTrainingsUseCase: ListTrainingsUseCase) : ViewModel() {

    private val _state: MutableStateFlow<ListTrainingsState> = MutableStateFlow(ListTrainingsState())
    val state: CommonFlow<ListTrainingsState> = _state.asCommonFlow()

    fun getTrainings(type: TrainingListTimeType) {

        listTrainingsUseCase(type).collectCommon { result ->
            when (result) {
                is Resource.Error -> {
                    _state.value = ListTrainingsState(error = result.message ?: "")
                }
                is Resource.Loading -> {
                    _state.value = ListTrainingsState(isLoading = true)
                }
                is Resource.Success -> {
                    _state.value = ListTrainingsState(
                        trainings = result.data ?: emptyList(),
                        isLoading = false
                    )
                }
            }
        }

    }

}

fun <T> Flow<T>.collectCommon(
    coroutineScope: CoroutineScope? = null,
    callback: (T) -> Unit,
): Job {
    return onEach {
        callback(it)
    }.launchIn(coroutineScope ?: CoroutineScope(Dispatchers.Main))
}
How can i solve this issue ?
👀 1
by the way i tried to use @Factory and @KoinViewModel annotations but it didn't work
10 Views