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?
RxSwift is a framework for interacting with the Swift programming language, while RxCocoa is a framework that makes Cocoa APIs used in iOS and OS X easier to use with reactive techniques. ReactiveX frameworks provide a common vocabulary for tasks used repeatedly across different programming languages.
Variable is a concept added into RxSwift in its early days which basically let you create an imperative bridge by “setting” and “getting” a current value to and from it. It was a seemingly helpful measure to get developers started with RxSwift until they fully understand “Reactive Thinking”.
Start using RxSwift with MVVM pattern At first, we need to add RxSwift to the project. In this example, we'll use CocoaPods but you can also use Carthage and Swift Package Manager. Check the GitHub repo for more info. RxSwift adds the basic library including Observable, Variable, PublishSubject etc.
Rx-Swift is a reactive programming library in iOS app development. It is a multi-platform standard, its difficult-to-handle asynchronous code in Swift, that becomes much easier in Rx-Swift. RxSwift makes easy to develop dynamic applications that respond to changes in data and respond to user events.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With