RxSwift곰튀김예시
작성일
// Model
struct Menu {
var name: Stirng
var price: Int
var count Int
}
// viewModel
class MenuListViewModel {
let menus: [Menu] = [
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
]
let itemsCount: Int = 0
let totalPrice: Int = 0
}
// VC에선
let viewModel = MenuListViewModel() 객체생성후
let munu = viewModel.menus.[indexPath.row]
menu.name
"\(munu.price)"
등등으로 사용하면 된다.
//viewModel다시보기
class MenuListViewModel {
let menus: [Menu] = [
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
]
let itemsCount: Int = 0
let totalPrice: Int = 0
}
계속 관찰하고싶으면
class MenuListViewModel {
lazy var menuObservable = PublishSubject<[Meun]>()
lazy var totalPrice = menuObservable.map {
$0.map { $.price * $0.count }.reduce(0, +)
}
init() {
let menus: [Menu] = [
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
Menu(name: "튀김1", pirce: 100, count: 0),
]
munuObservable.onNext(menus)
}
}
첫번째 map에선 menus가 내려가고 두번째 map에선 그안에 객체 하나하나 씩 들어간다.
realm배열을 바라보고있다가,
배열이 새로 들어오면, 그 배열을 위해 테이블뷰를 리로드해줄수 있다.
viewModel.menuObservable
.bind(to: tableView.rx.items(cellIdentifier: String, cellType: Cell.Type))
// cellIdentifier은 Cell의 identifier 이고
let cellId = "MenuItemTableViewCell"
// cellType은 MenuItemTableViewCell(클래스) 이다.
즉,
.bind(to: tableView.rx.items(cellIdentifier: cellId, cellType: MenuItemTableViewCell.self))
이렇게 작성하면 return값이
{index, item, cell in }이런 클로져가 나온다
여기서 item은 메뉴에들어있던 메뉴하나, index는 indexpath.row가, cell은 MenuItemTableViewCell의 인스턴스가 들어온다.
총 정리한 코드는
viewModel.menuObservable
.bind(to: tableView.rx.items(cellIdentifier: cellId, cellType: MenuItemTableViewCell.self)) {
cell.title.text = item.name
cell.price.text = "\(item.price)"
cell.count.text = "\(item.count)"
}
.disposed(by:disposeBag)
이러면 menuObservable이 바뀌면 테이블뷰에 계속 전달이 되는데, cell은이런방법으로 바꿔라라고 지정해주는 것이다.
이걸 작성하고나면, 테이블뷰의 데이터소스는 필요 없어진다.
여기서 menuObservable은 BehaviorSubject<[Menu]>(value: []) 로 되어있어야한다.
일단 작동되는지 확인하려면,
어떤 눌리는 버튼 {
viewModel.menuObservable.onNext([
Menu(name: "changed", price: 100, count 2)
])
}
그리고
viewModel.menuObservable
.bind(to: tableView.rx.items(cellIdentifier: cellId, cellType: MenuItemTableViewCell.self)) {
cell.title.text = item.name
cell.price.text = "\(item.price)"
cell.count.text = "\(item.count)"
}
에서 + - 처리를 하려면
Cell에서 처리를 해줘야한다.
class MenuItemTableViewCell에 가서 클로져를 만들고
var onChnage: ((Int) -> Void)? // Int을 보내줄꺼니까
+버튼 () {
onChange?(+1)
}
-버튼 () {
onChange?(-1)
}
이런 방식으로 만들어주고,
Menu를 바꿔줘야한다.
init() {
let menus: [Menu] = [
Menu(id: 0, name: "튀김1", pirce: 100, count: 0),
Menu(id: 1, name: "튀김1", pirce: 100, count: 0),
Menu(id: 2, name: "튀김1", pirce: 100, count: 0),
Menu(id: 3, name: "튀김1", pirce: 100, count: 0),
]
munuObservable.onNext(menus)
}
viewModel에 가서 changeCount메서드르 정의해주고,
func changeCount(item: Menu, incresase: Int) {
_ = menuObservable
.map { $0.map { m in
if m.id == item.id {
return Menu(id: m.id, name: m.name, price: m.price, count: m.count + increase )
} else {
return Menu(id: m.id, name: m.name, price: m.price, count: m.count )
}
}
.take(1)
.subcribe(onNext: {
self.menuObservable.onNext($0)
})
}
viewModel.menuObservable
.bind(to: tableView.rx.items(cellIdentifier: cellId, cellType: MenuItemTableViewCell.self)) {
cell.title.text = item.name
cell.price.text = "\(item.price)"
cell.count.text = "\(item.count)"
cell.onChange = { [weak self] incresase in
self?.viewModel.changeCount(item, incresase)
}
}
이런식으로 동작하게 만들면 된다.