InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.09k stars 719 forks source link

Koin Initialization Issue with Kotlin Multiplatform Mobile (KMM) on iOS #2016

Open BirdUshenin opened 1 month ago

BirdUshenin commented 1 month ago

Hello! I encountered a problem while integrating Koin for dependency injection in a Kotlin Multiplatform Mobile (KMM) project with modularization. Specifically, the issue arises on iOS when trying to inject some class in Helper class.

Scenario: I have the main app gradle module where I start Koin:

HelperIosKoin.kt:

fun initKoin() {
   startKoin {
       modules(geoPositionModule())
   }
}

Also, I have a geoposition gradle module which is responsible for providing geo-location data. This gradle module has some GeoPositionProvider class and the corresponding Koin module:

GeoPositionProvider.kt:

class GeoPositionProvider {

   fun getPosition(): String = "My current geo is (0,0)"

}

I add GeoPositionProvider class to the DI Graph this way:

GeoPositionModule.kt:

fun geoPositionModule() = module {
   single { GeoPositionProvider() }
}

In iOS part I have the following code to initialise Koin in the project:

iOSApp.swift:

@main
struct iOSApp: App {

   init() {
       HelperIosKoinKt.doInitKoin()
   }

   var body: some Scene {
       WindowGroup {
           ContentView()
       }
   }
}

And I want to inject my GeoPositionProvider class in the ContentView file. To do so, I have the corresponding Helper class. My helper class looks like this:

GeoPositionProviderHelper.kt:

class GeoPositionProviderHelper: KoinComponent {

   private val geoPositionProvider: GeoPositionProvider by inject()

   fun getGeo(): String = geoPositionProvider.getPosition()

}

ContentView.swift:

struct ContentView: View {
   let geo = GeoPositionProviderHelper().getGeo()

   var body: some View {
      Text(geo)
   }
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
      ContentView()
   }
}

The issue: If I locate my GeoPositionProviderHelper class in the main app gradle module, in the same module where I start Koin, everything works fine.

But if I locate GeoPositionProviderHelper class in the geoposition gradle module, in the same module where GeoPositionProvider class is stored and where I have geoPositionModule Koin module, I get the app crash with the following exception: kotlin.IllegalStateException: KoinApplication has not been started

Could you please tell me what is the cause of this problem? Is it possible to have Helper class not in the app gradle module, but in another gradle module?

Environment: Kotlin version: [kotlin = "2.0.20"] Koin version: [koin = "3.6.0-Beta4"]

Let me know if you need any additional details or steps to reproduce this issue. Thanks!

arnaudgiuliani commented 1 day ago

From what I see here, you could have a race condition because of your usage of KoinComponent. It will evaluate your Koin context to prepare your lazy field.