hi, is there a recommended way to consume a `State...
# mvikotlin
t
hi, is there a recommended way to consume a
State
directly from SwiftUI (ie, avoiding the
State -> Model
translation and avoiding creating a class that implements
BaseMviView
)? My project's equivalent of MainController in the sample exposes a
Flow<State>
that I consume directly from Compose with
Flow<T>.collectAsStateWithLifecycle()
and I'd like to follow as closely as possible with my SwiftUI
I found one option for translating a
Flow
to a
Publisher
that seems OK but requires new boilerplate code for every
Flow
instance but the article is 2 years old so I don't know if there's a simpler option available now (or, especially, a solution geared toward MVIKotlin usage)
a
In this case you could expose it as something like CFlow wrapper, and observe it as usual in SwiftUI.
So I would define CStateFlow wrapper in the shared module and wrap the Store's StateFlow. Then convert it to ObservableObject in Swift.
t
ah, so like the pattern used in this example?: • appstoreCFlowutil
a
Yes something like this! Except maybe the naming. I would create a Kotlin class like:
Copy code
class WrappedStateFlow<T : Any>(
    source: Flow<T>,
    private val context: CoroutineContext = Dispatchers.Main.immediate,
) : StateFlow<T> by source {
    fun subscribe(onNext: (T) -> Unit): Cancellation {
        val scope = CoroutineScope(context)
        scope.launch { collect(onNext) }
        return Cancellation { scope.cancel() } 
    }

    fun interface Cancellation {
        fun cancel()
    }
}
You can also define an extension like
fun <T : Any> StateFlow<T>.wrap(): WrappedStateFlow<T> = WrappedStateFlow(this)
And just expose
WrappedStateFlow
instead of
StateFlow
.
t
great, thank you!
just to be sure, the
source
param should be defined as
source: StateFlow<T>
, right?
a
Oh correct!
I wrote that code in Slack 😀
t
😄
I'm still trying to parse
fun interface Cancellation
. I guess it's a work-around for the fact that interfaces can't be instantiated? I'm just surprised that works :)
a
That just to shorten the instantiation 😀 just a shorter syntax for anonymous object.
t
ah, yeah. I would have used
object :
since I didn't know about this shortcut
a
Just make sure you are collecting the flow on Main.immediate dispatcher, as updating the state synchronously on the same call stack is very important sometimes (avoids glitches with text fields, etc.)