RxSwift를 21일간 공부하는 루틴
"Rx를 기깔나게 쓰는 신입개발자 도전" 시작 🚀
RxCocoa를 활용하여, TableView에 데이터를 표시해보면서 지금까지 공부해본것을 리뷰해보려고 한다.
이번 구현도 나의 취미은 크로스핏을 예제로 들었다.
조금더 이해를 돕기위해 살짝 설명을 하자면,
크로스핏에선 운동을 WOD(Workout Of the Day)라고 칭한다.
- 운동이름 : WOD의 이름을 나타낸다.
- 카테고리 : 유명한 와드들은 Girl's Name이나 Hero 라는 카테고리를 가진다.
- 상세동작 : 와드에서 수행해야할 동작들이다.
- 무게레벨링 : rx 는 와드에서 제공하는 최고 레벨의 무게이다.
1. 운동 이름, 카테고리, 상세 동작, 무게 레벨링 을 포함하는 데이터를 테이블뷰에 띄운다.
2. 각 셀을 탭 했을때, alert으로 운동이름과, 상세동작을 띄어준다.
🛠 라이브러리
- rxswift
- rxcocoa
- snapkit
만약 rx를 사용하지 않는다면 delegate 를 사용해서 구현을 했었을 것이다.
하지만 rx를 사용한다면 delegate없이 데이터 Observable과 table View 를 바인딩하여 cell에 뿌려줄 수 있다.
이런 기능을 가능하게 해주는 메서드 중 셀을 파라미터로 전달하는 메서드를 사용해보았다.
public func items<Sequence: Swift.Sequence, Cell: UITableViewCell, Source: ObservableType>
이 메서드와 달리, 셀을 파라미터로 전달하지 않는 메서드도 있다.
이 두부분은 추후에 비교해보겠다.
// 클로저로 전달되는 파라미터 row, element, cell
// 파라미터로 전달되는 cell은 RXTableViewCell.self로 타입캐스팅 되서 전달됨
allObservable.bind(to: tableView.rx.items(cellIdentifier: RXTableViewCell.registerID, cellType: RXTableViewCell.self)) { [weak self] row, element, cell in
// 셀 구성
cell.setData(element)
}
.disposed(by: disposeBag)
RXTableViewCell
은 커스텀으로 구현한 테이블뷰 셀이다.
4개의 UILabel을 snapkit을 활용해 구현하였다.
cell.setData(element)
는 label의 text에 각각의 값을 넣어주는 역할을 한다.
func setData(_ dataEntity : CrossfitMovements) {
categoryLabel.text = dataEntity.category.rawValue
nameLabel.text = dataEntity.name
movementsLabel.text = dataEntity.movements
levelLabel.text = dataEntity.level
}
본론으로 돌아와, rx로 구현한 코드를 보면 delegate로 구현했을때보다 훨씬 간단하고 직관적이다.
왜냐하면 delegate로 구현한다 생각하면, numberOfRowsInSection
과 cellForRowAt
를 활용해 return 할 row의 수와 UITableViewCell을 지정해줘야하기 때문이다.
하지만 rx로 구현한다면, 굳이 row의 수를 return하는 함수를 쓸 이유가 없다.
delegate를 사용한다면, didSelectRowAt
를 사용할 수 있다.
이러한 역할을 해주는 메서드는 rx에도 존재한다.
definition 에서 보이듯이 결국은 delegate를 감쌌다고 볼 수 있다.
itemSelected
의 경우 셀 선택시 next 이벤트를 전달하고 indexPath가 저장이 된다.
또한 바로 model의 데이터 값을 주는 메서드인 modelSelected
가 있다. 이땐 model의 type도 같이 넘겨줘야한다.
다시 돌아와, itemSelected
를 써서, 탭한 셀의 gray backgroundcolor가 유지되는 것을 없애보았다.
tableView.rx.itemSelected
.bind { [weak self] indexPath in
self?.tableView.deselectRow(at: indexPath, animated: false)
}
.disposed(by: disposeBag)
delegate와 비교했을때, rx의 장점이 있는 것은 분명하지만, 단점도 몇가지 느꼈다.
rx에서 제공해주는 메서드가 없는 경우도 있다.
예를 들어 section을 나누고 싶지만, RxDataSources
라이브러리를 사용해야 구현할 수 있다.
전체코드는 링크를 걸어놓았다.
두번째 구현인 alert 띄우는 부분은 다음 글에서 정리해보도록 하겠다.
회고
rx 를 활용했을때, 시너지가 나는 부분과 굳이 사용하지 않아도 되는 부분은 언제든지 존재할 것 같다.
이런 부분을 잘 캐치해내는 개발자가 되어야겠다.
물론 개인적의 시각의 차이가 있겠지만, 내가 왜 여기서 rx를 썼고 혹은 왜 여긴 rx를 쓰지 않았는지에 대한 로직을 갖고 개발을 해야겠다.
그리고 로직을 잘 정리하고 팀원들에게 조리있게 말할수 있는 개발자가 되어야겠다.
그렇지만... 조리있게 글쓰고 말하는 거.. 너무 어렵다.☹️