xxfast
08/04/2022, 1:26 AMState
from StateFlow<State>
to SwiftUi as @ObservedObject
? Rather than doing
@Published var state: State = State.companion.DEFAULT
viewModel.onState { (state) in
self.state = state
}
hfhbd
08/04/2022, 7:00 AMJohn O'Reilly
08/04/2022, 7:32 AMRick Clephas
08/04/2022, 3:23 PM@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).xxfast
08/05/2022, 7:44 AM-new-mm
variant
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 thinkJohn O'Reilly
08/05/2022, 7:45 AMxxfast
08/05/2022, 7:58 AMhfhbd
08/05/2022, 7:58 AMxxfast
08/08/2022, 12:03 AM// commonMain
class LoginViewModel(..) : ViewModel() {
private val stateFlow: MutableStateFlow<LoginState> = MutableStateFlow(defaultState)
val states: StateFlow<LoginState> = stateFlow.asStateFlow()
}
on ios, i have
class LoginViewModelDelegate: ObservableObject {
@Published var state: LoginLoginState = LoginLoginState.companion.DEFAULT
private let viewModel: LoginLoginViewModel = AppModule.LoginModule().viewModel
private var stateCollection: Task<Void, Error>? = nil
func collect() {
stateCollection = Task {
let states = asyncStream(for: viewModel.statesNative)
for try await _state in states {
self.state = _state
}
}
}
func cancel() {
stateCollection?.cancel()
}
}
and the swiftUi view looks like
struct LoginScreen: View {
@StateObject private var viewModelDelegate = LoginViewModelDelegate()
var body: some View {
LoginView(
state: viewModelDelegate.state,
onChange: { state in
viewModelDelegate.onChange(state: state)
},
onSubmit: { state in
viewModelDelegate.onSubmit(state: state)
}
)
.onAppear(perform: viewModelDelegate.collect)
.onDisappear(perform: viewModelDelegate.cancel)
}
}
This works, but i dont like it 🤔 Is there a way to avoid having two "ViewModel"s ( view model and the delegate) here?Rick Clephas
08/08/2022, 5:16 AMalex009
08/08/2022, 6:07 AMhfhbd
08/08/2022, 7:05 AMstruct 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 @alex009John O'Reilly
08/08/2022, 8:20 AM.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
?xxfast
08/08/2022, 8:32 AMJohn O'Reilly
08/08/2022, 8:33 AMfor await
? Perhaps some differences in iOS versions for thosexxfast
08/08/2022, 8:35 AMJohn O'Reilly
08/08/2022, 8:38 AMtask
requires iOS15.....I think that was originally case for async/await but I believe that at least got back ported to earlier version.....xxfast
08/08/2022, 8:39 AMJohn O'Reilly
08/08/2022, 8:40 AMxxfast
08/08/2022, 8:41 AMJohn O'Reilly
08/08/2022, 8:46 AMRick Clephas
08/08/2022, 8:49 AMYeah if I am not mistaken only Swift concurrency has been back ported to iOS 13, SwiftUI and Combine async APIs haven’t.requires iOS15.....I think that was originally case for async/await but I believe that at least got back ported to earlier version.....task
John O'Reilly
08/08/2022, 8:50 AM