Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jamiepinkham/d35904a1eb4d7d0c5d0f6304c003ac33 to your computer and use it in GitHub Desktop.
Save jamiepinkham/d35904a1eb4d7d0c5d0f6304c003ac33 to your computer and use it in GitHub Desktop.
//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!
//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() {
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 }
//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)
.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