wafflestudio / seminar-2021

2021 Rookies 세미나
47 stars 110 forks source link

RxSwift bind의 역할 및 Syntax 관련 질문 #608

Closed shp7724 closed 2 years ago

shp7724 commented 2 years ago

안녕하세요.

아래는 RxSwift 깃헙에서 발견한 예제인데요.

let searchResults = searchBar.rx.text.orEmpty
    .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
    .distinctUntilChanged()
    .flatMapLatest { query -> Observable<[Repository]> in
        if query.isEmpty {
            return .just([])
        }
        return searchGitHub(query)
            .catchAndReturn([])
    }
    .observe(on: MainScheduler.instance)

searchResults
    .bind(to: tableView.rx.items(cellIdentifier: "Cell")) {
        (index, repository: Repository, cell) in
        cell.textLabel?.text = repository.name
        cell.detailTextLabel?.text = repository.url
    }
    .disposed(by: disposeBag)

여기서 bind의 작동 방식을 소스 코드를 보면서 이해하려고 했는데, 잘 이해가 가지 않는 부분이 있습니다. 일단 bind의 여러 시그니처 중 위와 가장 가까워보이는 것이

public func bind<Observer: ObserverType>(to observers: Observer...) -> Disposable where Observer.Element == Element {
        self.subscribe { event in
            observers.forEach { $0.on(event) }
        }
    }

이건데요. 제가 가진 의문은 아래와 같습니다.

  1. to 파라미터에 tableView.rx.items(cellIdentifier: "Cell")과 클로저 하나가 들어갔는데, 둘 다 ObserverType인건가요? 특히 tableView.rx.items(cellIdentifier:)Disposable을 리턴한다고 나와 있던데, 서로 완전히 다른 게 아닌지 의문이 들었습니다.
  2. bind에 들어간 클로저의 정체가 무엇인가요? 그리고 해당 클로저의 시그니처는 어떻게 알 수 있나요?

감사합니다!

Ethan-MoBeau commented 2 years ago

메소드 스펙을 보시고 싶으시면 깃헙에서 뒤지시는 것보다는 control+command 누르고 메소드 이름을 좌클릭하면 뜨는 구현체 이동으로 확인할 수 있습니다

제가 보기는 public func bind<R1, R2>(to binder: (Self) -> (R1) -> R2, curriedArgument: R1) -> R2 를 사용하신 것 같아요

그리고 사실 저도 RxSwift 내부의 원리를 정확히 알지는 못해서... 답변 드리기가 좀 조심스럽네요. 보통 오픈소스는 그 원리를 다 파악하고 쓰는 경우는 잘 없는 것 같긴해요 물론 정확히 알고 있으면 더 효율적으로 쓸 수 있는건 사실이지만... 시간 나실 때 Rx 관련 강의를 아예 하나 들어보시는 걸 추천 드립니당

shp7724 commented 2 years ago

Jump to Definition 써도 해당 클로저의 시그니처까지는 알기 어렵더라구요.

질문 설명이 좀 부족했던 것 같은데, 제가 가장 궁금했던 점은

searchResults
    .bind(to: tableView.rx.items(cellIdentifier: "Cell")) {
        (index, repository: Repository, cell) in  // <- 이 부분에 어떤 인자가 전달되는지 알고 싶습니다.
        cell.textLabel?.text = repository.name
        cell.detailTextLabel?.text = repository.url
    }
    .disposed(by: disposeBag)

위 코드를 작성할 때 클로저에 (index, repository: Repository, cell)이 인자로 들어온다는 것은 어떻게 알수 있는지였습니다..!

Ethan-MoBeau commented 2 years ago

아 저건 ConfigureCell 이라는 type이 (CollectionViewSectionedDataSource

, UICollectionView, IndexPath, Item) -> UICollectionViewCell 를 typealias 한거라 그렇습니다

ConfigureCell이 이름은 Cell인데 사실 closure 형태라서요. 우리가 구독하는 데이터를 받아와서 rx.items에서 셀의 형태로 가공하고, ConfigureCell을 우리가 저 클로저 안에서 구현해서 cell에 데이터를 세팅하고 나면 rx가 알아서 이를 datasource 형태로 wrapping해서 뷰에 쏴주는 방식입니다