보통은 기획서 ( 어떤 기능 있는지 ) 나온 뒤 BE, Design 작업 완료되면 그에 따라서 개발하는 것으로 생각 → 동시에 개발할 수는 없을까 ?
‘기능’ 위주로 먼저 개발하고, 디자인이 나오면 그에 맞게 개발 백엔드 나오면 그에 맞게 모델명 변경하면서 개발

해당 뷰를 표시하기 위해서는
이렇게 총 3가지가 필요
struct Menu {
var name: String
var count: Int
var price: Int
}
→ View 의 Model 이기 때문에 ViewModel 이라 힘
MenuListViewModel 생성
class MenuListViewModel {
var menus: [Menu] = [
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
]
var totalPrice: Int = 0
var itemsCount: Int = 0
}
버튼을 눌렀을 때 UI 가 변경되도록 하려면 현재 상황에서는 버튼을 누를 때마다 하단 func 가 실행되어야 함
func updateUI() {
viewModel.totalPrice += 100
self.totalPrice.text = "\\(viewModel.totalPrice)"
}
이런 반복적인 함수 실행을 막기 위해 RxSwift 사용
Observable<Int> 로 바꾸기override func viewDidLoad() {
super.viewDidLoad()
viewModel.totalPrice
.map { $0.currencyKR() }
.subscribe(onNext: {
self.totalPrice.text = $0
})
.disposed(by: disposeBag)
}
🚨 여기서 문제 발생 🚨
버튼을 누를 때마다 VM 의 totalPrice 가 변경되어야 하는데, Observable<Int> 타입이어서 안됨 → Observable 은 값을 받아오는 애이기 때문에 외부에서 컨트롤 할 수는 없음
이걸 해결하기 위해 나온게 Subject
→ Subject 는 Observable 처럼 외부에서 값을 받아올 수도 있고, 통제할 수도 있음
class MenuListViewModel {
var menus: [Menu] = [
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
]
// var totalPrice: Observable<Int> = 0
**var totalPrice: PublishSubject<Int> = PublishSubject()**
var itemsCount: Int = 0
}
이렇게 정의한다면, 아래와 같은 프로세스 가능
func onOrder() {
viewModel.totalPrice.onNext(100)
}
위와 같이 진행하면, VM 의 totalPrice 를 100 으로 설정
PublishSubject 란?BehaviorSubject 란?AsyncSubject 란?ReplaySubject 란?그러면 눌렀을 때마다 100씩 추가시키려면 ?
viewModel.totalPrice
**.scan(0, accumulator: +)**
.map { $0.currencyKR() }
.subscribe(onNext: {
self.totalPrice.text = $0
})
.disposed(by: disposeBag)
.scan 을 사용
→ 0부터 시작해서, 새로운 값이 들어오면 기존 값에 더해준다
→ 100, 200, 300, ….
이전에 updateUI() 메소드를 실행할 때에는,
self.totalPrice.text = $0 를 계속 실행하여 업데이트 하는 식이었는데,
이런 방식으로 바꾸면, subscribe 를 한 번만 하면,
onNext 가 호출 될 때마다 알아서 업데이트를 시켜줌
→ updateUI() 를 매번 호출해주지 않아도 됨
따라서 아래와 같이 선언해두면, 따로 textLabel 의 text 값을 변경시키는 코드를 매번 실행시키지 않더라도 알아서 UI 가 업데이트 됨
override func viewDidLoad() {
super.viewDidLoad()
viewModel.itemsCount
.map { "\\($0)" }
.subscribe(onNext: {
self.itemCountLabel.text = $0
})
.disposed(by: disposeBag)
viewModel.totalPrice
.map { $0.currencyKR() }
.subscribe(onNext: {
self.totalPrice.text = $0
})
.disposed(by: disposeBag)
}
class MenuListViewModel {
var menuObservable = PublishSubject<[Menu]>()
lazy var itemsCount = menuObservable.map {
$0.map { $0.count }.reduce(0, +)
}
lazy var totalPrice = menuObservable.map {
$0.map { $0.count * $0.price }.reduce(0, +)
}
init() {
let menus: [Menu] = [
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
.init(name: "튀김1", count: 0, price: 1000),
]
menuObservable.onNext(menus)
}
}
이와 같이 menuObservable 하나의 변화가
itemsCount 와 totalPrice 를 조절하게 되는데, 이런 흐름을 Stream 이라고 함