Has anyone figured out a nice way to bridge a `Sta...
# ios
x
Has anyone figured out a nice way to bridge a
State
from
StateFlow<State>
to SwiftUi as
@ObservedObject
? Rather than doing
Copy code
@Published var state: State = State.companion.DEFAULT

viewModel.onState { (state) in
  self.state = state
}
Found this, but has there been any more development on the best approach for this?
h
j
@xxfast following more recent article talks about using that KMP-NativeCoroutines library https://johnoreilly.dev/posts/kmp-native-coroutines/
Using that in most samples now and really like it
r
Some useful operators for Swift: • https://developer.apple.com/documentation/combine/publisher/assertnofailure(_:file:line:)https://developer.apple.com/documentation/combine/publisher/assign(to:) I would probably go with something like:
Copy code
@Published var state: State = viewModel.stateNativeValue

createPublisher(for: viewModel.stateNative).assertNoFailure().assign(to: &$state)
Maybe it’s event possible to create a custom property wrapper of it (haven’t tried that yet).
x
loving kmp-native-coroutines, the plugin does makes things easier. Though i should say i've been running into this exception getting thrown (im using the
-new-mm
variant
Copy code
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: Trying to access top level value not marked as @ThreadLocal or @SharedImmutable from non-main thread
I'll post this one as a seperate thread i think
j
You have enabled use of new memory model?
x
I derped - forgot to enable this aaand its working 🙌 thanks guys
h
Just use 1.7.20-Beta, it is enabled by default 😄
r
Technically you can. Using property wrappers. Here is a POC https://gist.github.com/rickclephas/4c2ab99add21688001168886f759fa50 Though it has a major limitation, you can't access instance members in the propery wrapper constructor. But maybe that isn't needed if you can somehow wrap the StateObject as well.
a
check this post - i implement viewmodel binding without swift observableobject wrapper
h
Alternative you can use the closure initialer for parameter based StateObject:
Copy code
struct Login: View {
    init(viewModel: @autoclosure @escaping () -> LoginViewModel) {
        self._viewModel = StateObject(wrappedValue: viewModel())
    }

    @StateObject var viewModel: LoginViewModel

    @State private var error: Failure? = nil
    @State private var disableLogin = true

    var body: some View {
        Form {
            TextField("Username", text: viewModel.binding(\.userName))
            SecureField("Password", text: viewModel.binding(\.password))
And custom bindings to map a flow to Swift.Binding: https://github.com/hfhbd/ComposeTodo/blob/main/iosApp/Shared/ViewModel.swift Based on @alex009
j
@xxfast one minor comment about code above.....could you use
.task
view modifier in SwiftUI to call
viewModelDelegate.collect
(which becomes
async
function)....with automatic cancellation then when view disappears (so shouldn't need I think
cancel
?
x
Yeah I saw that, xcode told me that it is not supported for my min iOS target 🤔
j
but you were still able to use
for await
? Perhaps some differences in iOS versions for those
x
Let me check the exact error again
j
task
requires iOS15.....I think that was originally case for async/await but I believe that at least got back ported to earlier version.....
x
Ah, that explains it
j
what iOS version are you targetting?
x
14, need to support n-1 :(
j
ok, so maybe when iOS 16 comes out soon you can start using iOS 15 stuff 🙂
r
task
requires iOS15.....I think that was originally case for async/await but I believe that at least got back ported to earlier version.....
Yeah if I am not mistaken only Swift concurrency has been back ported to iOS 13, SwiftUI and Combine async APIs haven’t.
j
It's a pity....the combination of 2 is pretty compelling