[iOS] RxSwift 와 UI Cell 을 함께 사용할때 생각할 것들

김상우·2023년 10월 2일
0
post-custom-banner

iOS 에서의 UI Cell 재활용

iOS 개발할 때 사용하게 되는 UI Cell.

  • UITableViewCell
  • UICollectionViewCell

iOS 에서 이 Cell 들을 사용할때는, 보여줘야할 Cell 들을 모두 새롭게 생성하는 것이 아니라 화면에 보이는 부분만 생성하고 재활용하는 로직을 수행한다. 메모리 효율성을 고려한 것.

이 때 일반적으로, 셀을 재활용하기전에 초기화해야하는 세팅들을 prepareForReuse() 라는 메서드 안에 코드 작성한다.


Cell with RxSwift

RxSwift 와 UITableViewCell / UICollectionViewCell 을 함께 사용할 때 유의하면 좋을 2가지.

  1. 각 Cell 에 대한 구독(subscribe)을 했을 경우, prepareForReuse 안에 구독 해제(dispose) 코드를 반드시 작성한다.

  2. cell 내부에 disposeBag 이 있다면, cell 의 disposeBag 을 사용한다.


1. prepareForReuse 안에서 구독 해제하기

// TableViewCell
class SomeTableViewCell: UITableViewCell {
	var disposeBag = DisposeBag()
    let button = UIButton()
    
    ...
    
    override func prepareForReuse() {
    	super.prepareForReuse()
         // prepareForReuse 에서 명시적 구독 해제를 해야한다.
        disposeBag = DiposeBag()
    }
}

// 셀 외부에서 셀 내부 이벤트 스트림을 구독할 수 있다.
extension Reactive where Base: SomeTableViewCell {
	var buttonTapped: ControlEvent<Void> { base.button.rx.tap }
}

SomeTableViewCell 이라는 Cell 내부에서 스트림이 발생하고, 이 스트림을 외부에서 구독할 경우가 있을 수 있다.

이 경우 prepareForReuse() 에서 명시적 구독 해제를 해주지 않으면 재활용하게되는 다른 셀에서 재활용된 구독을 하기 때문에 원하지 않는 엉뚱한 값을 받게 된다.

button 의 title 값을 prepareForReuse 에서 초기화 해주지 않았을 경우 다른 셀에서 의도되지 않은 title 값을 받을 수 있게 되는 현상과 같은 논리.


2. Cell 내부의 disposeBag 사용하기.

class SomeViewController: UIViewController {
	
    // ...
    
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(SomeTableViewCell.self, for: indexPath)
        guard let item = dataSource[safe: indexPath.row] else { return cell }
        
        // 위에서 선언했던 셀 내부 스트림을 구독해서 사용한다.
        cell.rx.buttonTapped
        	.subscribe {
            	// ... 구독해서 사용할 뭔가의 행동
            }
            // 셀에 속한 스트림이기 때문에 셀의 생명주기에 맞게 구독해제한다.
            .disposed(by: cell.disposeBag)
}

RxSwift 를 사용하다보면, disposed(by: disposeBag) 을 무의식에 습관처럼 쓰게 된다.

cell 의 스트림인 경우에는 disposeBag 이 아닌 cell.disposeBag 에 처리해줄 수 있도록 유의하는 것이 좋다.

profile
안녕하세요, iOS 와 알고리즘에 대한 글을 씁니다.
post-custom-banner

0개의 댓글