Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional features for creating Binding from the SwiftUI side #237

Open
kramlex opened this issue Apr 12, 2023 · 0 comments
Open

Add additional features for creating Binding from the SwiftUI side #237

kramlex opened this issue Apr 12, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@kramlex
Copy link
Contributor

kramlex commented Apr 12, 2023

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))
    }
}
@Alex009 Alex009 added the enhancement New feature or request label Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants