tableView.rx.items
UITableView의 items을 빼주는
다음 두 파일을 살펴보면, View와 ViewModel 간의 역할 분리 및 관계를 알 수 있음.
// PriceTextFieldCellViewModel.swift
import RxSwift
import RxCocoa
struct PriceTextFieldCellViewModel {
// View <- ViewModel
let showFreeShareButton: Signal<Bool>
let resetPrice: Signal<Void>
// View -> ViewModel
// MARK: View에서 전달 받아서 이곳에서 위의 변수들을 처리하도록 함. (다시 View에 영향 가도록)
let priceValue = PublishRelay<String?>()
let freeShareButtonTapped = PublishRelay<Void>()
init() {
self.showFreeShareButton = Observable
.merge(
priceValue.map { $0 ?? "" == "0" },
freeShareButtonTapped.map { _ in false } // 보여진 버튼을 누르면 showFreeShareButton은 false 즉, 다시 숨겨지도록
)
.asSignal(onErrorJustReturn: false)
self.resetPrice = freeShareButtonTapped
.asSignal(onErrorSignalWith: .empty())
}
}
// PriceTextFieldCell.swift
import UIKit
import SnapKit
import RxSwift
import RxCocoa
class PriceTextFieldCell: UITableViewCell {
let disposeBag = DisposeBag()
let priceInputField = UITextField()
let freeShareButton = UIButton()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
attribute()
layout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func bind(_ viewModel: PriceTextFieldCellViewModel) {
// MARK: 2) ViewModel에서 처리한 것을 바탕으로 -> View에 영향 가도록
viewModel.showFreeShareButton
.map { !$0 }
.emit(to: freeShareButton.rx.isHidden)
.disposed(by: disposeBag)
viewModel.resetPrice
.map { _ in "" }
.emit(to: priceInputField.rx.text)
.disposed(by: disposeBag)
// MARK: 1) 이게 먼저 View -> ViewModel로 가면
priceInputField.rx.text
.bind(to: viewModel.priceValue)
.disposed(by: disposeBag)
freeShareButton.rx.tap
.bind(to: viewModel.freeShareButtonTapped)
.disposed(by: disposeBag)
}
private func attribute() {
freeShareButton.setTitle("무료나눔 ", for: .normal)
freeShareButton.setTitleColor(.orange, for: .normal)
freeShareButton.setImage(UIImage(systemName: "xmark"), for: .normal)
freeShareButton.titleLabel?.font = .systemFont(ofSize: 18)
freeShareButton.tintColor = .orange
freeShareButton.backgroundColor = .white
freeShareButton.layer.borderColor = UIColor.orange.cgColor
freeShareButton.layer.borderWidth = 1.0
freeShareButton.layer.cornerRadius = 10.0
freeShareButton.clipsToBounds = true
freeShareButton.isHidden = true
freeShareButton.semanticContentAttribute = .forceRightToLeft
priceInputField.keyboardType = .numberPad
priceInputField.font = .systemFont(ofSize: 17)
}
private func layout() {
[priceInputField, freeShareButton].forEach {
contentView.addSubview($0)
}
priceInputField.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
freeShareButton.snp.makeConstraints {
$0.top.bottom.leading.equalToSuperview().inset(15)
$0.width.equalTo(100)
}
}
}
combineLatest(){}
let errorMessages = Observable
.combineLatest(
titleMessage,
categoryMessage,
detailMessage
) { $0 + $1 + $2 }
withLatestFrom(){} // trigger 역할 하고 싶을 때
self.presentAlert = submitButtonTapped // 이걸 trigger로 하기 위해 withLatestFrom
.withLatestFrom(errorMessages) { $1 }
.map(model.setAlert)
.asSignal(onErrorSignalWith: .empty())