Thread
#multiplatform
    m

    Michal Klimczak

    1 year ago
    What is the state-of-the-art solution for concurrency when exposing KMM to iOS? I was thinking coroutines native-mt + some wrapper which can be transformed to Swift Combine but I'm not seeing a lot of this on github tbh and there's some boilerplate to glue it all together.
    Javier

    Javier

    1 year ago
    Decompose project has a Observable which is compatible, easily, with iOS
    m

    Michal Klimczak

    1 year ago
    Javier

    Javier

    1 year ago
    Yeah
    I think Flow is not easy to use on iOS side yet. I don't know if they are waiting until Swift code generation which will not arrive with Kotlin 1.5.
    John O'Reilly

    John O'Reilly

    1 year ago
    It's just proof of concept level at this stage but fwiw I created Combine Publisher that wraps a Kotlin flow coming from shared kmp code....described in https://johnoreilly.dev/posts/kotlinmultiplatform-swift-combine_publisher-flow/
    m

    Michal Klimczak

    1 year ago
    @Javier what do you mean by swift code generation? Are there any plans for kotlin native support for swift maybe? Because then we might build Combine wrappers directly in the Kotlin code and that would be awesome.
    Not sure what this symbol means, but I guess it's paused? 😞
    Javier

    Javier

    1 year ago
    Currently kotlin is only generating objective c code
    I think that paused item is related to an option to generate swift code
    Generics with kotlin-obj-c are awful because you need to cast later in Swift
    m

    Michal Klimczak

    1 year ago
    @John O'Reilly I use a similar approach but I'm having some second thoughts, mainly because I'm looking for an elegant yet flexible way of handling the CoroutineScope inside swift code. Also there's no way to make an extensions for a generic class, because of lack of swift interoperability.
    in yoiur example you are using MainScope() for iosScope, so you assume that you will always launch your coroutine from the main thread, right?
    John O'Reilly

    John O'Reilly

    1 year ago
    In this particular case I am.....with typically calling main-safe methods from ktor
    but original example in https://dev.to/touchlab/working-with-kotlin-coroutines-and-rxswift-24fa @russhwolf uses background thread and shows various
    freeze
    methods that need to be called when doing that
    m

    Michal Klimczak

    1 year ago
    it seems like that's gonna be the most usual case so I'm thinking of using the MainScope() by default to avoid explicitly accessing the scope from swift code.
    the original article has been writter before coroutine native-mt I think
    but I'm starting my work from main thread in swift and then making network calls on Dispatchers.Default with ktor without any issues.
    russhwolf

    russhwolf

    1 year ago
    My article does take native-mt into account, but it assumes you might switch threads from the Swift side and so does extra work to make sure that's safe. If your Swift code is all main-threaded it will simplify things.
    nrobi

    nrobi

    1 year ago
    @Michal Klimczak our approach was to leave the CoroutineScope handling to the Kotlin world (a simple
    dispose()
    ) and for the generics part expose some convenience lambdas. It doesn’t scale as well, but we wanted something more seamless on the swift side. It might depend on your use-case/architecture as well, but you can find an example here
    m

    Michal Klimczak

    1 year ago
    @russhwolf I used your approach and have all the freezes where you had them, but I tried launching from different threads in swift and it crashes (with the IncorectDereferrence of course) when I use a different thread on the swift side and on kotlin launch side. I.e. when I launch from
    RunLoop.main
    and then use
    Dispatchers.Main
    in SuspendWrapper it's all good. I also succeeded with using
    Dispatchers.Default
    and something specific for the Combine side, but can't remember. Will perform some tests and get back to you.
    @nrobi this is a shared viewmodel approach which will not work for me, but it gives m another angle, thanks 🙂
    @russhwolf okay, so the problem is not with passing the data through the suspendwrapper, but the scope, I think...
    .receive(on: DispatchQueue.global())
                .flatMap { username in
                    createPublisher(
                        scope: coroutineScope,
                        wrapper: loadUserUseCase.loadUser(username: username)
                    )
    When I do this I get
    Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared kotlinx.coroutines.internal.ContextScope@4f9348 from other thread
    I guess this is just not something that I should do - I mean the
    createPublisher
    has to be done on the original thread that touched the
    coroutineScope
    param, otherwise I'm in trouble, right? Or am I reading it all wrong?
    russhwolf

    russhwolf

    1 year ago
    That error is saying that your
    coroutineScope
    is being accessed across threads and needs to be frozen.
    Arkadii Ivanov

    Arkadii Ivanov

    1 year ago
    You may also want to check an alternative library: https://github.com/badoo/Reaktive It brings absolute multi-threading freedom in Native. Except freezing is still a thing in some cases. There are thread pools for computation and IO tasks, you can freely jump/switch between threads, update UI without freezing it, etc. It can also be exposed to Swift with just
    .wrap()
    extension function.