HBu
HBu

Reputation: 559

What does the following example code from RxSwift/RxCocoa do?

I'm trying to understand in detail

.drive(resultsTableView.rx_itemsWithCellIdentifier("WikipediaSearchCell",
       cellType: WikipediaSearchCell.self)) 
          { (_, viewModel, cell) in
              cell.viewModel = viewModel
          }

from WikipediaSearchViewController.swift lines 47-64. I've tried to extract the arguments to look at the concrete type signatures, but a rewrite to

    let temp1 = searchBar.rx_text
        .asDriver()
        .throttle(0.3)
        .distinctUntilChanged()
        .flatMapLatest { query in
            API.getSearchResults(query)
                .retry(3)
                .retryOnBecomesReachable([], reachabilityService: ReachabilityService.sharedReachabilityService)
                .startWith([]) // clears results on new search term
                .asDriver(onErrorJustReturn: [])
        }
        .map { results in
            results.map(SearchResultViewModel.init)
    }

    let driveArg1 = resultsTableView.rx_itemsWithCellIdentifier("WikipediaSearchCell", cellType: WikipediaSearchCell.self)
    let driveArg2 = { (_, viewModel: SearchResultViewModel, cell: WikipediaSearchCell) in
        cell.viewModel = viewModel
    }
    temp1.drive(driveArg1, curriedArgument: driveArg2)
        .addDisposableTo(disposeBag)

gives

cannot invoke 'rx_itemsWithCellIdentifier' with an argument list of type '(String, cellType: UITableViewCell.Type)'

for driveArg1 and

type of expression is ambiguous without more context

for driveArg2.

The signatures of drive and rx_itemsWithCellIdentifier are

public func drive<R1, R2>(with: Self -> R1 -> R2, curriedArgument: R1) -> R2 {}

public func rx_itemsWithCellIdentifier(cellIdentifier: String, cellType: Cell.Type = Cell.self)(source: O)(configureCell: (Int, S.Generator.Element, Cell) -> Void) -> Disposable {}

but at this point Swift syntax is darn incomprehensible for me. Can anyone explain the signatures and what happens in the code?

Upvotes: 11

Views: 2826

Answers (1)

tomahh
tomahh

Reputation: 13661

Here, Swift compiler cannot infer the type of driveArg1 and driveArg2 because of a lack of context. When used inline within the drive() call, the compiler have more clues as of what the type of each parameter can be, and we end-up not needing to annotate for those types.

Taking this into account, lets try to add type annotation for those two variables.

First, we'll update the signature of rx_itemsWithCellIdentifier with swift 2.2 in mind, removing the confusing currying syntax and also adding the generic annotations

public func rx_itemsWithCellIdentifier
  <S: SequenceType, Cell: UITableViewCell, O : ObservableType where O.E == S>
  (cellIdentifier: String, cellType: Cell.Type = Cell.self)
    -> (source: O)
    -> (configureCell: (Int, S.Generator.Element, Cell) -> Void) 
    -> Disposable

Type of driveArg2

It's the argument we pass to curriedArgument of drive(), and will be the argument we pass to rx_itemsWithCellIdentifier after applying (source: O). Thus, it needs to match (Int, S.Generator.Element, Cell) -> Void

There are two unknown in this type definition, S.Generator.Element and Cell. They are generic, so we need to figure out what they are.

  • Cell is easy, it's the type of the cell we want to configure, here WikipediaSearchCell.
  • S.Generator.Element is a bit harder, but we can figure it out pretty easily. We get from O.E == S that the type of the sequence is the type we find between the angle bracket of our source element. In our case, source (temp1) is of type Observable<[SearchResultViewModel]>. So S's type is [SearchResultViewModel] hence, S.Generator.Element will be SearchResultViewModel

Good, we now have the signature of driverArg2:

(Int, SearchResultViewModel, WikipediaSearchCell) -> Void

To simplify what comes next, lets define a typealias for it

typealias CellConfigurator = (Int, SearchResultViewModel, WikipediaSearchCell) -> Void

We can now define driveArg2

let driveArg2: CellConfigurator = { (_, viewModel: SearchResultViewModel, cell: WikipediaSearchCell) in
    cell.viewModel = viewModel
}

Type of driveArg1

Now that driveArg2 is out of the way, figuring out the type driveArg1 of gets easier. It is simply the return type of rx_itemsWithCellIdentifier, with the generic portion replaced

typealias DriveArg2Type = (source: Observable<[SearchResultViewModel]>) -> (CellConfiguration) -> Disposable

drive signature

With all this expanded, the type signature for drive hopefully makes more sense:

drive(Self -> R1 -> R2, curriedArgument: R1) -> R2
// where
Self = Observable<[SearchResultViewModel]>
R1 = CellConfigurator
R2 = Disposable

Upvotes: 4

Related Questions