Reputation: 559
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
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
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
}
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
signatureWith 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