Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two-way binding in Swift Combine (UIKit)

I have a UITableViewCell that contain a UISwitch. This cell has its own SwitchCellViewModel. Lets say it contains some Bool value (enabled vs disabled). And ViewController is the one who contains UITableView, creates viewModel for the cell and sets cell with it.

I want to a achieve:

  1. On a cell level: change UISwitch state whenever a viewModel’s bool property value changes (without reloading tableView of course).
  2. On a ViewController level: handle UISwitch state change (by user).

The use case is next: cell shows some option that can be disabled or enabled. That action goes to backend, and after I receive response with a result (enabled vs disabled on backend), I have to sync view’s state again with the updated data.

I understand how to subscribe to a property value change on a cell level, so when I change it in viewModel from viewController, it updates a cell view right away. But I’m not sure how to deal with back action from UISwitch to viewController.

Is it achievable with a single @Published bool property in viewModel, or I have to have 2 separate things for this bidirectional case.

It looks really silly to me that I have to expose a separate Publisher for this purpose, since I already have a @Published property in viewmodel, that view controller should be notified about, so why wouldn’t I use it. But if I use just one, then it will be the case that ViewController sets @Published var in viewModel, cell itself will handle it and adjust UI, but ViewController immediately gets event about it as well, since it is subscribed to on it.

like image 435
Stas Ivanov Avatar asked Dec 21 '20 10:12

Stas Ivanov


People also ask

Can you use combine with UIKit?

It's probably not a coincidence that Combine happened to be introduced at the exact same time as SwiftUI. While Combine can certainly also be used with both UIKit and AppKit, as well as within scripts and command line tools, its highly declarative design often makes it a perfect logic companion to SwiftUI-based views.

Can we use combine in Swift?

The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.

What is two way binding in Mvvm Swift?

So, this picker doesn't just read the value of paymentType , it also writes the value. This is what's called a two-way binding, because any changes to the value of paymentType will update the picker, and any changes to the picker will update paymentType .

Does SwiftUI import combine?

A perfect example of that is what you are experiencing, where SwiftUI imports Combine , but you can't use Just in your code without explicitly importing Combine yourself. However, this isn't true all of the time. For example, CGFloat is defined in CoreGraphics , but you have access to it if you import SwiftUI .


1 Answers

@Published is a one-way data flow - it, along with ObservableObject, synthesize a combine publisher chain that sends updates (half-duplex, or one-way) when the values "will change". It doesn't send the value that's changed, only a signal that something changed.

To get a data flow back to the model, you'll need to invoke something or trigger that back-data flow from UISwitch activating. It could be as simple as a callback method to update the model where you're keeping the state - and that's where I'd generally start.

like image 69
heckj Avatar answered Sep 20 '22 17:09

heckj