Я создаю пользовательский пошаговый режим многократного использования.
![enter image description here](https://i.stack.imgur.com/sQLpM.png)
У меня все работает, и я использую Combine для наблюдения за изменениями значений. Однако я хотел бы улучшить его, используя двустороннюю привязку данных, но не уверен, что это возможно?
Вот мой текущий код:
class Stepper: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
@Published var count = 0
private let stackView = UIStackView()
private let minusButton = BorderedRoundButton()
private let plusButton = BorderedRoundButton()
private let countLabel = UILabel()
private var cancellables = Set<AnyCancellable>()
func setup() {
translatesAutoresizingMaskIntoConstraints = false
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
minusButton.setTitleColor(.primaryTint, for: .normal)
plusButton.setTitleColor(.primaryTint, for: .normal)
minusButton.setTitle("-", for: .normal)
plusButton.setTitle("+", for: .normal)
countLabel.text = "0"
countLabel.textColor = .blackText
countLabel.font = .preferredFont(forTextStyle: .body)
countLabel.textAlignment = .center
stackView.addArrangedSubview(minusButton)
stackView.addArrangedSubview(countLabel)
stackView.addArrangedSubview(plusButton)
minusButton.tapPublisher.sink { [weak self] _ in
self?.count -= 1
}.store(in: &cancellables)
plusButton.tapPublisher.sink { [weak self] _ in
self?.count += 1
}.store(in: &cancellables)
$count.map { "\($0)" }.assign(to: \.text, on: countLabel).store(in: &cancellables)
$count.map { $0 > 0 }.assign(to: \.isEnabled, on: minusButton).store(in: &cancellables)
addSubview(stackView)
NSLayoutConstraint.activate([
minusButton.widthAnchor.constraint(equalToConstant: 38),
minusButton.heightAnchor.constraint(equalToConstant: 38),
plusButton.widthAnchor.constraint(equalToConstant: 38),
plusButton.heightAnchor.constraint(equalToConstant: 38),
countLabel.widthAnchor.constraint(equalToConstant: 44),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}
}
И я использую его вот так:
class PickerViewController: UIViewController {
@IBOutlet private var stepper: Stepper!
private var cancellables = Set<AnyCancellable>()
@Published var count = 0
override func viewDidLoad() {
super.viewDidLoad()
stepper.count = count
stepper.$count.sink { [weak self] value in
self?.count = value
}.store(in: &cancellables)
}
}
И это бит, который я хочу улучшить: теперь мне нужно оба установить начальное значение и затем наблюдать за изменениями. Я знаю, что это вряд ли много кода, но мне просто интересно, могу ли я сделать это в одну строку, с своего рода двусторонним связыванием данных? перестроил его версию, чтобы не импортировать SwiftUI), чтобы PickerViewController.count
был единственным источником, и Stepper автоматически обновил бы его. Однако, тогда у меня проблема в том, что @Bindable
сам по себе не наблюдается, поэтому эти строки больше не будут работать:
$count.map { "\($0)" }.assign(to: \.text, on: countLabel).store(in: &cancellables)
$count.map { $0 > 0 }.assign(to: \.isEnabled, on: minusButton).store(in: &cancellables)
Поэтому мой вопрос: могу ли я улучшить код для использования двустороннего связывания данных, или я должен просто придерживаться установки значения и затем наблюдать его отдельно?