Instantly share code, notes, and snippets.

Embed
What would you like to do?
// This is the traditional version of the RxSwift-based gist posted here:
// https://gist.github.com/cliss/51cb740b14f3cd56ba1d11f2a9a6ba02
// This won’t compile and it surely has errors.
// (The same may be true as the original.)
// Some things are obviously omitted.
// It's meant as illustrative rather than as actual running code.
//
// The problem being solved:
// There is a text field. When you type in it, all changes are coalesced
// for 0.3 seconds, and then an HTTP call is made, and a table is updated
// with results.
// Also: there's a Refresh button, and tapping the Refresh button
// runs that same HTTP call and updates the table with results.
// Whenever there's an existing HTTP call, and a new one has been triggered,
// the existing HTTP call should be canceled.
struct Result {
let text: String
let someOtherThing: String
}
typealias FetcherCallback = (result: Result?, error: NSError?) -> Void
class Fetcher {
let task: NSURLSessionDataTask
init(query: String, callback: FetcherCallback) {
//Assume the url was created based on the query. And that myURLSession came from somewhere.
self.task = myURLSession.dataTaskWithURL(url) { data, response, error in {
if let error = error {
callback(nil, error)
return
}
let results: [Result] = something //make results from the data; obvious omission for the sake of argument
callback(results, nil)
}
}
self.task.resume()
}
func cancel() {
task.cancel()
}
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private weak var tableView: UITableView!
private weak var textField: UITextField!
private var fetchTimer: NSTimer?
private var fetcher: Fetcher?
private var results = [String]() {
didSet {
tableView.reloadData()
}
}
private var currentText = "" {
didSet {
if currentText.count < 4 {
invalidateFetchTimer()
}
else {
resetFetchTimer()
}
}
}
deinit {
invalidateFetchTimer()
cancelExistingFetch()
}
override func viewDidLoad() {
textField.delegate = self
}
func textDidChange(sender: AnyObject) {
if currentText != textField.stringValue {
currentText = textField.stringValue
}
}
private func invalidateFetchTimer() {
if let timer = fetchTimer where fetchTimer.isValid {
timer.invalidate()
}
fetchTimer = nil
}
private func resetFetchTimer() {
invalidateFetchTimer()
fetchTimer = NSTimer(timeInterval: 0.3, target: self, selector: #selector(fetchTimerDidFire(_:)), userInfo: nil, repeats: false)
}
dynamic func fetchTimerDidFire(sender: AnyObject) {
runFetch()
}
private func cancelExistingFetch() {
if let existingFetcher = fetcher {
existingFetcher.cancel()
}
fetcher = nil
}
private func runFetch() {
invalidateFetchTimer()
cancelExistingFetch()
fetcher = Fetcher(text: currentText) { result, error in
if let error = error {
//Handle it.
}
else {
self.results = result.map { oneResult in return oneResult.text }
}
}
}
@IBAction func refresh(sender: AnyObject) {
runFetch()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment