https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
a

AndreiBogdan

03/21/2024, 5:19 PM
Hello, I'm using @Rick Clephas's library for view models combined with the KMP-
NativeCoroutine
library so I can use StateFlow on iOS. The problem I'm having is it seems it doesn't want to work with generics. I have the below (focus on
uiState
):
Copy code
open class BaseViewModel<U, R> internal constructor(
    uiStateDefault: U,
    private val redirectTypeDefault: R
) : KMMViewModel() {

    protected val redirectBehaviorSubject = BehaviorSubject(Redirect(redirectTypeDefault))

    protected val uiStateMutable = MutableStateFlow(viewModelScope, uiStateDefault)

    @NativeCoroutinesState
    val uiState: StateFlow<U> =uiStateMutable.asStateFlow()

    val redirectObservable: ObservableWrapper<Redirect<R>> =
        redirectBehaviorSubject.wrap()
    
    // ....
}
and while on Android it WORKS, on iOS it doesn't. It does see the
uiState
but it's seen as
Any?
and iOS needs to cast it to whatever
U
is in order for it to work. Is it a limitation of the
NativeCoroutine
library; am I using it wrong ?!; is it a limitation of KMM itself ?! I would like not to define
uiState
on each viewModel subclass so iOS can see it properly ... does anyone have an idea how to solve this and keep it generic ? :(
r

Rick Clephas

03/21/2024, 5:28 PM
Yeah that is indeed a limitation. KMP-NativeCoroutines generates extensions functions which don’t support generics. Since you are using
NativeCoroutinesState
and just need the actual value you can do the following manually:
Copy code
@HiddenFromObjC
val uiState: StateFlow<U> =uiStateMutable.asStateFlow()

@ObjCName("uiState")
val uiStateValue: U get() = uiState.value
This is basically what is normally generated as an extension property, but as a member property which solves the generics limitation
a

AndreiBogdan

03/21/2024, 5:30 PM
hmm, but that will not trigger a recompose when the value changes, will it ?
recompose or whatever the swiftUI thing is called 😄 I think it's a view ... anyway ..
r

Rick Clephas

03/21/2024, 5:31 PM
State changes will still be propagated to Swift(UI)
The magic for that is in
MutableStateFlow(viewModelScope, uiStateDefault)
a

AndreiBogdan

03/21/2024, 5:31 PM
ah, ok!
r

Rick Clephas

03/21/2024, 5:31 PM
Once you update the value of that MutableStateFlow the changes are propagated to Swift
a

AndreiBogdan

03/21/2024, 5:31 PM
that's awesome then !!
trying it right now ! thank you very much !
👍🏻 1
hmm, so .. i just realized, i don't even need the @NativeCoroutinesState annotation then ...
r

Rick Clephas

03/21/2024, 5:33 PM
Correct. It is just an easy way to create the value property for 99% of the cases.
a

AndreiBogdan

03/21/2024, 5:34 PM
fingers crossed! thank you
woot. it worked! the only thing is that it sees it a nullable even though it's always got a default value. ios dev needs to use
uiState?.someField
... Not sure if there's anything I can do about that though 🤔
r

Rick Clephas

03/21/2024, 6:27 PM
Hmm good question, Maybe the following?:
BaseViewModel<U: Any, R>
m

Michael Krussel

03/21/2024, 7:14 PM
The interop with Objective-C doesn't handle nullable generics in general, so I've avoided it in all my public generics.
a

AndreiBogdan

03/27/2024, 8:42 AM
@Rick Clephas i forgot to mention, setting U: Any worked perfectly ! Thank you !
👍🏻 1
2 Views