Add additional features for creating Binding from the SwiftUI side
kramlex opened this issue · comments
Mark Dubkov commented
add the ability to state the current value for a specific view, and not on the view in which the StateObject/ObservedObject for the ViewModel was created
here is an example:
ViewModel+Binding.swift
class SubscriptionBag: ObservableObject { }
extension ObservableObject where Self: ViewModel {
func binding<T, R>(
_ flowKey: KeyPath<Self, CMutableStateFlow<T>>,
equals: @escaping (T?, T?) -> Bool,
getMapper: @escaping (T) -> R,
setMapper: @escaping (R) -> T,
to bag: SubscriptionBag
) -> Binding<R> {
let stateFlow: CMutableStateFlow<T> = self[keyPath: flowKey]
var lastValue: T? = stateFlow.value
var disposable: DisposableHandle? = nil
disposable = stateFlow.subscribe(onCollect: { value in
if !equals(lastValue, value) {
lastValue = value
bag.objectWillChange.send()
disposable?.dispose()
}
})
return Binding(
get: {
getMapper(stateFlow.value!)
},
set: {
stateFlow.value = setMapper($0)
}
)
}
}
SomeScreen.swift
struct SomeScreen: View {
@StateObject private var viewModel: SomeViewModel
init() {
_viewModel = StateObject(wrappedValue: ...)
}
var body: some View {
SomeScreenContent()
.environmentObject(viewModel)
}
}
SomeScreenContent.swift
struct SomeScreenContent: View {
@EnvironmentObject var viewModel: SomeViewModel
@StateObject private var subscriptionBag = SubscriptionBag()
var body: some View {
TextField(placeholderText, text: viewModel.binding(\.text, to: subscriptionBag))
}
}