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)
	}
}
이런식으로 동작하게 만들면 된다.