Kodein
Kodein copied to clipboard
App freezing when using iOS
dependency - org.kodein.di:kodein-di-framework-compose:7:20:1
Im injecting a ScreenModel from the Voyager library and all is working well when i run the app on Android, but if i try to run it on iOS i get a vague error from xcode which i suspect is around memory management and the app freezes
Exception NSTaggedPointerString * 0x8000000105b9ffd5
self @thin iosApp.iOSApp.Type iosApp.iOSApp
Heres my screen model
class HomeScreenModel(
private val savedTeamRepository: SavedTeamRepository
) : CoreScreenModel<HomeState, HomeEvent, HomeEffect>(HomeState())
Im then using realm
class SavedTeamRepositoryImpl(
private val realm: Realm
) : SavedTeamRepository {
override suspend fun insert(savedTeam: SavedTeam) {
val dbTeam = savedTeam.toDbModel()
realm.write {
copyToRealm(dbTeam)
}
}
override suspend fun observeAll(): Flow<List<SavedTeam>> = flow {
val savedTeamsFlow = realm.query<DbSavedTeam>().asFlow()
savedTeamsFlow.collect { changes: ResultsChange<DbSavedTeam> ->
emit(changes.list.map { it.toEntity() })
}
}
}
Providing deps
val dataModule = DI.Module(name = "dataModule") {
bindSingleton { RealmConfiguration.create(schema = provideRealmSchemaObjects()) }
bindSingleton { Realm.open(instance()) }
bindProvider<SavedTeamRepository> { SavedTeamRepositoryImpl(instance()) }
}
val homeModule = DI.Module(name = "homeModule") {
bindProvider {
HomeScreenModel(instance())
}
}
private fun provideRealmSchemaObjects() = setOf(
DbSavedTeam::class,
DbPlayer::class,
DbOffset::class
)
Then eventually in my App composable
@Composable
fun App() = withDI(homeModule, dataModule) {
Navigator(HomeContent) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
AppContent(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
) {
CurrentScreen()
}
BottomNavBar(modifier = Modifier)
}
}
}
Also just to add this other error on xcode
Thread 1: signal SIGABRT
Having similar error when trying to start similar @Composable fun App() = withDI {...}
from XCode. @romainbsl do you plan to support Compose Multiplatform for iOS?
(Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
Stacktrace excerpt
#0 0x00000001033dc8b8 in kfun:org.kodein.di.DI.Module.<get-_name>#internal at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:592
#1 0x00000001033dc9f4 in kfun:org.kodein.di.DI.Module#<get-name>(){}kotlin.String at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:593
#2 0x00000001033f12c0 in kfun:org.kodein.di.internal.DIBuilderImpl#import(org.kodein.di.DI.Module;kotlin.Boolean){} at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIBuilderImpl.kt:278
#3 0x000000010340d230 in kfun:org.kodein.di.internal.DIBuilderImpl#import(org.kodein.di.DI.Module;kotlin.Boolean){}-trampoline at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIBuilderImpl.kt:277
#4 0x00000001033f1924 in <inlined-out:<anonymous>> [inlined] at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIBuilderImpl.kt:295
#5 0x00000001033f1914 in kfun:kotlin.collections#forEach__at__kotlin.Array<out|0:0>(kotlin.Function1<0:0,kotlin.Unit>){0§<kotlin.Any?>} [inlined] at /opt/buildAgent/work/2fed3917837e7e79/kotlin/libraries/stdlib/common/src/generated/_Arrays.kt:13309
#6 0x00000001033f1914 in kfun:org.kodein.di.internal.DIBuilderImpl#importAll(kotlin.Array<out|org.kodein.di.DI.Module>...;kotlin.Boolean){} at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIBuilderImpl.kt:295
#7 0x0000000103407984 in kfun:org.kodein.di.DI.Builder#importAll(kotlin.Array<out|org.kodein.di.DI.Module>...;kotlin.Boolean){}-trampoline at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:482
#8 0x00000001033dc660 in kfun:org.kodein.di.DI.Builder#importAll$default(kotlin.Array<out|org.kodein.di.DI.Module>...;kotlin.Boolean;kotlin.Int){} at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:482
#9 0x00000001021f14f8 in kfun:di.di$lambda$0#internal at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/di/Kodein.kt:20
#10 0x00000001021f2120 in kfun:di.$di$lambda$0$FUNCTION_REFERENCE$0.invoke#internal at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/di/Kodein.kt:19
#11 0x00000001021f2198 in kfun:di.$di$lambda$0$FUNCTION_REFERENCE$0.$<bridge-UNNN>invoke(org.kodein.di.DI.MainBuilder){}#internal at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/di/Kodein.kt:19
#12 0x00000001024ddfdc in kfun:kotlin.Function1#invoke(1:0){}1:1-trampoline at /Users/admin/.gradle/daemon/8.2.1/[K][Suspend]Functions:1
#13 0x00000001033fb0f4 in kfun:kotlin#apply__at__0:0(kotlin.Function1<0:0,kotlin.Unit>){0§<kotlin.Any?>}0:0 [inlined] at /opt/buildAgent/work/2fed3917837e7e79/kotlin/libraries/stdlib/src/kotlin/util/Standard.kt:83
#14 0x00000001033fb0d8 in kfun:org.kodein.di.internal.DIImpl.Companion.newBuilder#internal at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIImpl.kt:21
#15 0x00000001033fafc0 in kfun:org.kodein.di.internal.DIImpl#<init>(kotlin.Boolean;kotlin.Function1<org.kodein.di.DI.MainBuilder,kotlin.Unit>){} at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIImpl.kt:18
#16 0x00000001033dd590 in kfun:org.kodein.di.DI.Companion#invoke(kotlin.Boolean;kotlin.Function1<org.kodein.di.DI.MainBuilder,kotlin.Unit>){}org.kodein.di.DI at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:626
#17 0x00000001033dd678 in kfun:org.kodein.di.DI.Companion#invoke$default(kotlin.Boolean;kotlin.Function1<org.kodein.di.DI.MainBuilder,kotlin.Unit>;kotlin.Int){}org.kodein.di.DI at /Users/runner/work/Kodein/Kodein/kodein-di/src/commonMain/kotlin/org/kodein/di/DI.kt:626
#18 0x00000001021f0fd0 in kfun:di.$init_global#internal at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/di/Kodein.kt:19
#19 0x0000000102552f48 in CallInitGlobalPossiblyLock ()
#20 0x00000001021f1144 in kfun:di#<get-di>(){}org.kodein.di.DI at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/di/Kodein.kt:1
#21 0x00000001021f7f64 in kfun:screen#App(androidx.compose.runtime.Composer?;kotlin.Int){} at /Users/user/Documents/xcode/mingli_ios/projects/Mingli Font Viewer/composeApp/src/commonMain/kotlin/screen/App.kt:12
Hi, Actually I do use Kodein inside a Compose Multiplatform project, with Android and iOS. I was not able to reproduce it.
Do you have a simple reproducer project ?
@schmidt9 @alfietapping Just retried on CMP and it's ok. Do you do something special while creating your instances? like using coroutines or something?
Here is my (non) reproducer: KMP-DI-REPRODUCER.zip
@romainbsl your reproducer works, so problem seems to be in other dependency (Voyager), trying to figure out with a separate reproducer
voyagerVersion = "1.0.0"
...
// https://voyager.adriel.cafe/setup
implementation(libs.voyager.navigator)
implementation(libs.voyager.transitions)
implementation(libs.voyager.screenmodel)
// https://voyager.adriel.cafe/screenmodel/kodein-integration
implementation(libs.voyager.kodein)
I also usse voyager with Kodein on a CMP project. Given your context, can you try to reproduce it start from my project ?
Well I seem to find the cause (not obvious for me) - declaration order
import org.kodein.di.DI
import org.kodein.di.bindProvider
// declaration order matters:
// if you declare di (2) before homeScreenModule (1) crash occurs on both Android and iOS
// 1
val homeScreenModule = DI.Module(name = "homeScreen") {
bindProvider {
HomeScreenModel()
}
}
// 2
val di = DI {
importAll(
homeScreenModule
)
}
Well... This looks normal to me.
if you do something like
val di = DI { import(myModule) }
val myModule = DI.Module("whatever") { ... }
Using val di = DI
you are doing a direct assignement. Then DI { }
DSL is executed. So it tries to import the module with a reference this is NOT yet created.
This is like doing a function:
fun do() {
val a = b + 1 // b is unknown
val b = 2
}
However, with Kodein you can still declare (2) before (1) by using a lazy property, like:
// 2
val di by DI.lazy {
importAll(homeScreenModule)
}
// 1
val homeScreenModule = DI.Module(name = "homeScreen") {
bindProvider {
HomeScreenModel()
}
}
There is no compiler issue, as the DI lambda could be lazy, but the compiler knows nothing about this.
I closed the issue, but do not hesitate to reopen if needed.
thanks a lot for quick help, actually I'm not sure that @alfietapping has the same issue... but mine is solved