简体   繁体   中英

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?

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 OE == 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM