ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RxSwift - TableView, CollectionVIew를 사용해보자
    Ray Wenderlich/RxSwift 2020. 2. 29. 21:28

    Ch.18 Table and CollectionViews

    iOS앱에서 가장 많이 사용하는 UI는 UITableView, UICollectionVIew를 통해 데이터의 리스트를 표현하는 것이다. 

    보통은 delegate, dataSource의 콜백을 통해 데이터를 표현한다. 


    RxSwift를 사용하면 observable sequence를 TableView, CollectionView에 표현할 수 있음을 물론이고, 코드의 양도 줄일 수 있다. 

    UITableView, UICollectionView의 간단한 사용은 RxCocoa에 이미 포함되어 있다. 

    좀 더 심화적인 내용(섹션관리, 애니메이션 등)은 RxDataSources(https://github.com/RxSwiftCommunity/RxDataSources)를 통해 사용가능하다.


    Basic table view 

    UITableView를 사용하는 기본적인 시나리오에 대해 살펴보자. 

    화면에 도시 이름을 리스트로 표현할 것이다. 


    @IBOutlet var tableView: UITableView! 

    func bindTableView() { 

    let cities = Observable.of(["Lisbon", "Copenhagen", "London", "Madrid", "Vienna"]) 

    cities .bind(to: tableView.rx.items) { (tableView: UITableView, index: Int, element: String) in 

    let cell = UITableViewCell(style: .default, reuseIdentifier: "cell"

    cell.textLabel?.text = element 


    return cell

    }.disposed(by: disposeBag) 

    }

    ** UITableViewDataSource를 별도로 설정할 필요가 없다.


    코드를 이해해보자. 

    - tableView.rx.items는 observable sequence를 바인딩하는 펑션이다. 

    - 이 바인딩은 제공된 observable을 subscribe하는 가상의 ObserverType객체를 생성하고, 자신을 스스로 dataSource, delegate로 설정한다. 

    - 새로운 element의 배열이 observable에 전달되면, 이 바인딩은 테이블뷰를 reload한다.

    - 각 item에 해당하는 cell에 접근하기 위해, RxCocoa에 전달한 클로져가 수행된다.



    이게 보편적인 사용법이다. 그러면 사용자가 셀을 선택하는 경우는 어떻게 대처할 것인가?

    tableView.rx.modelSelected(String.self)

    .subscribe(onNext: { model in 

    print("\(model) was selected"

    }) 

    .disposed(by: disposeBag)


    사용자의 선택이 발생하면 modelSelected(_:) 메소드가 observable을 리턴한다. 

    유사한 기능으로 itemSelected()가 있다. (얘는 IndexPath를 전달해준다.)


    RxCocoa에서는 많은 observable을 제공한다. 

    modelSelected(_:), modelDeselected(_:), itemSelected, itemDeselected 

    itemAccessoryButtonTapped 

    itemInserted, itemDeleted, itemMove (셀 editMode에서) 

    willDisplayCell, didEndDisplayingCell (UITableViewDelegate에 있는 걔들 맞음)


    Multiple cell types 

    위에서는 하나의 셀 종류만 사용했다. 

    하지만 우리는 보통 여러 종류의 셀을 사용한다. 


    여러 모델과 셀을 사용하는 방법 중에서, enum을 사용하는 방법을 추천한다. 

    아무리 많은 셀 타입도 쉽게 관리할 수 있다. 

    String을 보여주는 셀, 2개의 이미지를 보여주는 셀 총 2개 타입의 셀을 사용한다고 가정해보자. 


    이에 해당하는 enum을 만들고, Observable을 만들어보자.


    enum MyModel { 

    case text(String) 

    case pairOfImages(UIImage, UIImage) 


    let observable = Observable<[MyModel]>.just([ 

    .textEntry("Paris"), 

    .pairOfImages(UIImage(named: "EiffelTower.jpg")!, UIImage(named: "LeLouvre.jpg")!), 

    .textEntry("London"), 

    .pairOfImages(UIImage(named: "BigBen.jpg")!, UIImage(named: "BuckinghamPalace.jpg")!) ]) 


    observable.bind(to: tableView.rx.items) { (tableView: UITableView, index: Int, element: MyModel) in 

    let indexPath = IndexPath(item: index, section: 0) 


    switch element { 

    case .textEntry(let title): 

    let cell = tableView.dequeueReusableCell(withIdentifier: "titleCell", for: indexPath) as! TextCell 

    cell.titleLabel.text = title 

    return cell 

    case .pairOfImages(let firstImage, let secondImage): 

    let cell = tableView.dequeueReusableCell(withIdentifier: "pairOfImagesCell", for: indexPath) as! ImagesCell 

    cell.leftImage.image = firstImage 

    cell.rightImage.image = secondImage 

    return cell 

    }

    }.disposed(by: disposeBag)



    Providing additional functionality 

    RxCocoa에서 지원하는 기능 외에도 직접 delegate역할을 하고 싶을 수 있다. 


    ViewController가 delegate역할을 하고 싶을 수 있다. (class ViewController: UICollectionViewDelegateFlowLayout) 

    예를 들어, UICollectionView에서 collectionView(_:layout:sizeForItemAt:)메소드를 사용하는 경우가 이에 해당한다. 


    nib또는 스토리보드에서 delegate로 연결시켜준다면 ViewController가 Delegate콜백을 전달 받을 수 있을 것이다. 

    혹은 이미 컬렉션뷰를 바인딩하였다면 아래 메소드를 사용하여 delegate를 설정하도록 하자. (delegate설정하는 순서가 상관있는듯??) 


    tableView.rx.setDelegate(myDelegateObject) tableView.delegate = self와 같은 직접적인 delegate설정은 오작동의 원인이 될 수 있다. 


    RxDataSources 

    RxCocoa는 테이블뷰, 컬렉션뷰의 많은 기능을 이미 제공하고 있다. 

    하지만 좀 더 심화 기능을 구현하고 싶을 수 있다. 셀 insert, delete 애니메이션이나 특정 섹션 리로드 등 RxDataSource을 사용하려면 배울것도 할것도 많지만 그만큼 강력한 기능을 제공한다. 

    https://github.com/RxSwiftCommunity/RxDataSources 를 참고하시길






Designed by Tistory.