Forked from cliss/gist:51cb740b14f3cd56ba1d11f2a9a6ba02
Created
April 9, 2016 10:57
-
-
Save kittinunf/64e9194ca0fd25209a5884df16abb8cb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//a somewhat contrived example of how reactive programming can be useful | |
//some real concerns that are omitted, but can be easily accomplished using rxswift are | |
//error handling, displaying loading indicators, etc | |
// A result object that comes from the network. | |
// The contents are irrelevant for this example. | |
struct Result { | |
let text: String | |
let someOtherThing: String | |
} | |
// An object that can get data from the network | |
struct Fetcher { | |
/** | |
Performs a network query, and returns 0 or more results as an array. | |
- Parameter query: The query to complete. Comes from the UI | |
- Returns: An observable with 0 or more results | |
*/ | |
static func performQuery(query: String) -> Observable<[Result]> { | |
// Go to the network | |
// Get data | |
// Transform into Result objects | |
// If the returned Observable is disposed, it will cancel the network request. | |
Observable.create { observer in | |
//standard building of a NSURLSessionDataTask | |
let task = myURLSession.dataTaskWithURL(url) { data, response, error in | |
guard let error == nil else { | |
//inform the observer there was an error | |
observer.onError(error) | |
return | |
} | |
let results: [Result] = //make results from the data | |
//inform the observer there were results | |
observer.onNext(results) | |
//inform the observer this observable will not send any more results | |
observer.onComplete() | |
} | |
//start the data task | |
task.resume() | |
//!!!! we return a Disposable instance that executes the given block when the observer is disposed of | |
//this is what gives us the "cancel inflight request" behavior | |
return AnoymousDisposable { | |
task.cancel() | |
} | |
} | |
} | |
} | |
/** | |
Some UI View Controller that has a UITextField on it | |
*/ | |
class ViewController: UIViewController: UITableViewDataSource, UITableViewDelegate { | |
weak var tableView: UITableView! | |
weak var textField: UITextField! | |
weak var button: UIButton! | |
//in your post, you described dispose bags as a "parallel memory mangement system" | |
//i liken them to more of an "resource clean up system" | |
//much like closing a file handle, or unsubscribing form NSNotifications | |
let disposeBag = DisposeBag() | |
//an array of strings we display in our table view | |
var results = [String]() | |
override func viewDidLoad() { | |
// Get the text field, throttled, filtered, distinct | |
let o: Observable<String> = | |
textField.rx_text | |
//only send me the text field's value every 3/10th of a second | |
.throttle(0.3) | |
//only send me the text field's value when it is different than before | |
.distinctUntilChanged() | |
//filter out queries less than 3 characters | |
.filter { query in return query.characters.count > 3 } | |
// Get button taps *with the latest value of the text field* | |
let p: Observable<String> = button.rx_tap.withLatestFrom(o) | |
// Merge the two and then carry on like our prior example. | |
// Merge requires observables with the same elemnt type. | |
// | |
// In short, the last value from o gets put into the | |
// observable stream for p; if *either* happens we should | |
// signal the observable. | |
let q: Observable<String> = Observable.of(o, p).merge() | |
//map expects that you return a type that can be converted to an observable | |
//such as an array which you see below in the other map | |
//since we are returning a function that returns an observable | |
//we need to flatten it so that we don't end up with a returned type of Observable<Observable<[Result]>> | |
//the "latest" uses the latest value emitted by the text field and disposes the other in-flight observables (network requests) | |
q.flatMapLatest { query in | |
Fetcher.performQuery(query) | |
//convert the Result struct into an array of strings | |
}.map { results in | |
// Extract the text out of this object; standard Swift. | |
results.map { result in return result.text } | |
} | |
//at this point we have an Observable<[String]> `o` that we can "subscribe" to | |
//subscribing to o will emit a new array of strings for every completed network request, | |
//which we use as the data in a table view | |
//there are better ways to display data in a tableview using rxcocoa, but for this simple example it should suffice | |
//any errors that may have happened will bubble up to our observable (ie, the network request failed), | |
//which we can subscribe to as well with a subscribeError(onError:((ErrorType) -> Void)). this has been omitted for clarity | |
o.subscribeNext { [weak self] results in | |
self?.results = results | |
self?.tableView.reloadData() | |
} | |
//table view code omitted for clarity | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Make
.swift
so it reads much better with syntax highlighting.