- Published on
๐ Swift - Rx ์์ด Reactive Binding ํด๋ณด๊ธฐ
- Authors
- Name
- ์ด์ฐฝ์ค
Rx ์์ด View โก๏ธ ViewModel Bindingํ๊ธฐ
Rx๋ผ๋ ๋ ๊ณต๋ถํ ๋ ์ด๋ ค์ ๋๋ฐ.. ํ ๋ฒ ์จ๋ณด๋๊น ์์ด ๊ธฐ๋ฅ ๊ตฌํ์ ํ ๋ ๊ฐ์ฆ์ด ๊ณ์ํด์ ์ผ์ด๋๋ ํ์์ ๊ฒช๊ณ ์์ต๋๋ค.
ํ์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํ๋ ๊ฒ์ ์ข์ง ์์ผ๋๊น Rx ์์ด ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ํ๋ ๋ฐฉ๋ฒ์ ๊ณต๋ถํด๋ณด์์ต๋๋ค.
์ฝ๋์ ๊ฒฝ์ฐ ๊ฒ์ํด๋ณธ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์๋ฌผ์์ ๋์ผํ ํํ๋ก ์ฌ์ฉ๋๊ณ ์์์ต๋๋ค. ๋ด๋ถ์ ์ธ ๋์ ๊ณผ์ ๋ ๋ชจ๋ฅธ์ฑ๋ก ๊ฐ์ ธ๋ค์ฐ๊ธด ์ซ์ด์ ๊ณต๋ถ ๊ฒธ ์์ฑํ ๊ฒ์๋ฌผ์ ๋๋ค!
์ฒดํฌ ๋ฆฌ์คํธ ์ฑ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํฉ์๋ค. ํ ์ผ์ ์๋ฃํ ๋๋ง๋ค ๊ทธ ๋ ์ผ์ ์๋ฃ์จ Label์ ๊ณ์ํด์ ๋ฐ๊ฟ์ฃผ๊ณ ์ถ์ด์. ๋ฑ Rx๋ฅผ ์ฌ์ฉํ๋ฉด ํธ๋ฆฌํ ์ํฉ์ด์ง๋ง ๋ค๋ฅธ ๊ธฐ๋ฅ์ ์ฐพ์๋ด ์๋ค.
๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค ์ํํ๋ ๋์.. ์ ํํ ํด๋น ๊ธฐ๋ฅ์ ํ๋ ์น๊ตฌ๊ฐ ์์๋ ๊ฒ ๊ฐ์์.
๋ฐ๋ก didSet
์
๋๋ค.
didSet
var donePercentage: Int = 0 {
didSet {
print(oldValue)
}
}
donePercentage
์ ๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค didSet
์ ์๋ print
ํจ์๊ฐ ์๋์ผ๋ก ํธ์ถ๋ฉ๋๋ค. ์ด didSet
์ ํค์๋๋ก ์ก๊ณ ์์ํด๋ณด๊ฒ ์ต๋๋ค.
Observable
Rx์์ ์ฐ๋ฆฌ๋
viewModel.todos
.subscribe(onNext: { todo in
print(todo.count)
})
.disposed(by: self.disposeBag)
์ด๋ฐ ์์ผ๋ก Observable
ํ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ subscribe
ํ์ฌ ํ์ํ ๋์๋ค์ ์ฒ๋ฆฌํด์ฃผ์์ต๋๋ค.
๋จผ์ ํ์ํ Observable
ํ์
์ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ง๋ค์ด๋ด
์๋ค.
value: T
class Observable<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
Observable
์ ๋ชจ๋ ํ์
์ ๋ํด์ ๊ด์ฐฐ์ด ๊ฐ๋ฅํด์ผํ๊ธฐ ๋๋ฌธ์ Generic
ํ์
์ T
๋ผ๋ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํด์ฃผ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์ฑ์๋ฅผ ํตํด ์๋งน์ด์ธ value
๊ฐ์ ๋ฃ์ด์ฃผ์์ฃ .
์ด value
๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค ์ด๋ค ํจ์๋ฅผ ์คํํด์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ didSet
์ ์ฌ์ฉํด์ค์๋ค.
var value: T {
didSet {
// ์คํํ ํจ์
}
}
listener (ํด๋ก์ )
๋ค์ Rx์ ๊ฒฝ์ฐ๋ฅผ ๋ด๋ณผ๊น์?
์ didSet
์์ ๋ค์ด๊ฐ๊ฒ ๋ ํจ์๋ฅผ ์ฐพ์๋ด
์๋ค.
.subscribe(onNext: { todo in
print(todo)
})
subscribe
๋ผ๋ ํจ์๋ฅผ ํธ์ถํ๊ณ ํด๋ก์ ์ ํํ๋ก ํจ์๋ฅผ ์ ๋ฌ๋ฐ์ ์คํํ๋ ๊ฒ ๊ฐ๋ค์.
๊ทธ๋ ๋ค๋ฉด ์์ ๋ค์ด๊ฐ ํจ์๋ฅผ ๋ด์ ํด๋ก์ ๋ณ์๋ฅผ ์ ์ํด์ค์๋ค.
var listener: ((T) -> Void)?
return
๋ฐ๋ ๊ฐ์ ์์ผ๋ Void
๋ก ์ฃผ๊ณ value
๊ฐ์ ๋ฐ์ ์ฒ๋ฆฌํด์ฃผ์ด์ผ ํ๋ input
ํ๋ผ๋ฏธํฐ๋ก T
(์ ๋๋ฆญ ํ์
)์ ๋ฐ์์ค์๋ค.
์ด์ ์ด listener
ํด๋ก์ ๋ฅผ Observable
์ฝ๋์ ์ ์ฉ์์ผ์ค์๋ค.
class Observable<T> {
var value: T {
didSet {
self.listener?(value)
}
}
var listener: ((T) -> Void)?
init(_ value: T) {
self.value = value
}
}
subscribe
View
์ชฝ์์ subscribe
์์์ ํด๋ก์ ๋ก ๋ฐ๋ ํจ์๋ฅผ listener
์ ๋ด๊ณ ์๋ค๊ฐ didSet
์ด ํธ์ถ๋๋ฉด ์คํ๋์ผํฉ๋๋ค.
๋ฐ๋ผ์ ํ๋ผ๋ฏธํฐ๋ก @escaping
ํด๋ก์ ๋ฅผ ๋ฐ์์ฃผ๊ณ ํด๋์ค ๋ด๋ถ์ listener
์ ๋ด์์ค์๋ค.
func subscribe(listener: @escaping (T) -> Void) {
listener(value)
self.listener = listener
}
์ด ๋ listener(value)
์ ๊ฐ์ด ํ ๋ฒ ์คํํด์คฌ๊ธฐ ๋๋ฌธ์, subscribe
์ ๋์์ ๋ฌด์กฐ๊ฑด ํ ๋ฒ์ ์คํ๋ฉ๋๋ค.
binding๊ณผ ๋์์ ์คํ์ ํ์ง ์๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ๋นผ์ฃผ์ด๋ ์๋ฌด ๋ฌธ์ ์์ต๋๋ค.
์ข ํฉ
์ด์ ์ฝ๋๋ค์ ํฉ์ณ๋ด ์๋ค!
class Observable<T> {
var value: T {
didSet {
self.listener?(value)
}
}
var listener: ((T) -> Void)?
init(_ value: T) {
self.value = value
}
func subscribe(listener: @escaping (T) -> Void) {
listener(value)
self.listener = listener
}
}
์ฌ์ฉ
class HomeViewModel {
var todoData: Observable<[ToDo]> = Observable([])
}
class HomeViewController: UIViewController {
private var viewModel = HomeViewModel()
lazy var progressLabel = UILabel().then { ... }
override func viewDidLoad() {
self.viewDidLoad()
self.viewModel.todoData.subscribe { todo in
DispatchQueue.main.async {
self.progressLabel.text = todo.count
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.viewModel.todoData.value = [
ToDo(title: "Test", state: .completed)
]
}
}
}