Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

swift

rx-swift

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?

like image 603
HBu Avatar asked Jan 07 '16 12:01

HBu


People also ask

What is RxSwift and RxCocoa?

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.

What is variable RxSwift?

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”.

How do I use RxSwift with MVVM?

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.

What is difference between Swift and RxSwift?

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.


1 Answers

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
like image 64
tomahh Avatar answered Jan 23 '23 03:01

tomahh