Hi everyone. I am trying to set up a usable archi...
# koin
m
Hi everyone. I am trying to set up a usable architecture where some dependencies in a KMP project are provided directly from swift's side. E.g. think an implementation of a class that performs navigation in ios app as a result of an event happening in the common code, namely the 401 https response causing navigation to login screen (ForcedLogoutHandler). So, I can easily initialize my koin from swift code and pass the dependencies there and then manually pass them to the modules that need them. E.g.
Copy code
fun initializeKoin(forcedLogoutHandler: ForcedLogooutHandler, ...)
But I will have a few of those and would like to leverage koin's modules and declare them in swift code. Think of sth like kotlin
Copy code
fun <T : Any> Module.registerSingleton(clazz: KClass<T>, definition: () -> T) {
    single(kClass = clazz, qualifier = null, createdAtStart = false, definition = { definition() })
}
swift
Copy code
let iosModule = DiHelper().createKoinModule { module in
                module.registerSingleton(clazz: ForcedLogoutNavigator.self) { ForcedLogoutNavigator() as ForcedLogoutHandler }
            }
Problem is, I don't think swift types are meant to be translatable to KClass in any way. At least I haven't found a way to do that. Reified type doesn't work either. How do you handle that kind of architecture pickle?
This works, hope that helps someone
Copy code
@Suppress("UNCHECKED_CAST")
@OptIn(BetaInteropApi::class)
fun <T : Any> Module.single(clazz: ObjCProtocol, definition: () -> T) {
    val kClazz = getOriginalKotlinClass(clazz) as KClass<T>
    single(kClass = kClazz, qualifier = null, createdAtStart = false, definition = { definition() })
}
Not that ObjCProtocol and ObjCClass here are not interchangeable and using one where another should be used will result in a very nasty EXC_BAD_ACC crash
👍 1
a
You can also provide the ios object definition in a kotlin module the iosMain variant, using kotlin language but an ios framework object. I tend do design my app like that since I try to use swift to a minimum necessary. It also simplifies a lot the setup.
When starting a new project that is easy, when you adapt an already existing project and want to rely on already existing stuff then you need to play differently probably.
m
I'm not sure I follow, can you show a snippet?
a
yep, check out this gradle module, it setups the room database, and has android side of deps, and ios side of deps, which depend on ios framwork android framework respectively. https://github.com/alexandrucaraus/kmp-sample-arch/tree/main/data/database
specifically the way you import the import platform.Foundation.NSFileManager in kotlin
m
ah, yeah, I got it now. This is fine for platform.Foundation stuff, however here the scenario is a bit different. It's a class that invokes and effect in the swiftui's navigation (so UI layer basically) of which the kotlin knows nothing about, since it's some kind of swift-side code / library etc. So it would probably never look good even when implemented on the kotlin side.
a
Copy code
import platform.UIKit.UIViewController

actual class NavigationController(private val rootViewController: UIViewController) {
    actual fun navigateTo(destination: String) {
        // Use UIKit's UINavigationController or UIViewController to handle navigation
        // Example: 
        val viewController = getViewControllerForDestination(destination)
        rootViewController.navigationController?.pushViewController(viewController, animated = true)
    }

    private fun getViewControllerForDestination(destination: String): UIViewController {
        // Map destination string to corresponding UIViewController
        // Return the corresponding view controller instance
    }
}
You can do stuff like that, but still you will need to pass the rootViewController from somewhere from swift
ok maybe for swiftui navigation it's a bit different
m
After all the main difference is how kotlin or swift specific you want your app to be. I want to stop on either viewmodels or repositories
a
true. On viewmodels its quite ugly since you need to handle lifecycles and coroutines scopes, and you need special viewmodel to do that, it's related to how coroutine scopes are handled in swift. And on repository side of things I think it's okayish, though the same coroutine scope will need to be tackled.