Last active
February 3, 2018 23:20
-
-
Save rnapier/b1f13be8d018bf4d145b 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
// Previous async code based on Result. A "Search" wraps an async operation and offers features like cancel(). | |
// An earlier experiment includes self.pages = result ?? [], but that's cheating. | |
// If you didn't care about error handling, what's the point of Result? Added displayError() to test reality. | |
// Of course maybe "self.pages = result ?? { displayError(err); return [] }()" would work, | |
// but that gets a little obtuse and scales poorly. | |
func search(text: String, completionHandler: (Result<[Page]>) -> Void) -> Search { ... } | |
self.currentSearch = self.searcher.search(searchString, completionHandler: { result in | |
switch result { | |
case .Success(let pages): | |
self.pages = pages | |
case .Failure(let err): | |
displayError(err) | |
self.pages = [] | |
} | |
self.tableView.reloadData() | |
} | |
///// | |
// New idea based on throws. Note use of "() throws -> T" as a replacement for Either | |
// The closure is a little funny, but it's actually shorter and less "noisy" than the Result approach | |
// when you take real error handling into account (calling displayError) | |
func search(text: String, completionHandler: (() throws -> [Page]) -> Void) -> Search { ... } | |
self.currentSearch = search(searchString, completionHandler: { result in | |
do { | |
try self.pages = result() | |
} catch { | |
displayError(err) | |
self.pages = [] | |
} | |
self.tableView.reloadData() | |
} | |
///////// | |
// Here's the Result-way that I handled processing that completion handler: | |
struct Operation<ResultType> { | |
let task: NSURLSessionDataTask | |
init(url: NSURL, queue: NSOperationQueue, parser: NSData -> Result<ResultType>, completionHandler: Result<ResultType> -> Void) { | |
let handler = operationHandler(queue: queue, parser: parser, completionHandler: completionHandler) | |
self.task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: handler) | |
self.task.resume() | |
} | |
func cancel() { | |
self.task.cancel() | |
} | |
} | |
private func operationHandler<T>(#queue: NSOperationQueue, #parser: NSData -> Result<T>, #completionHandler: Result<T> -> Void) | |
(data: NSData?, _: NSURLResponse?, error: NSError?) { | |
switch (data, error) { | |
case (_, .Some(let error)) where error.isCancelled(): | |
break // Ignore cancellation | |
case (_, .Some(let error)): | |
queue.addOperationWithBlock({completionHandler(.Failure(error))}) | |
case (.Some(let data), _): | |
queue.addOperationWithBlock({completionHandler(parser(data))}) | |
default: | |
fatalError("Did not receive an error or data.") | |
} | |
} | |
///////// | |
// And here's the throw-wrapped way: | |
struct Operation<ResultType> { | |
let task: NSURLSessionDataTask? | |
init(url: NSURL, queue: NSOperationQueue, parser: (NSData) throws -> ResultType, completionHandler: (() throws -> ResultType) -> Void) { | |
let handler = operationHandler(queue: queue, parser: parser, completionHandler: completionHandler) | |
self.task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: handler) | |
self.task?.resume() | |
} | |
func cancel() { | |
self.task?.cancel() | |
} | |
} | |
private func operationHandler<T>(queue queue: NSOperationQueue, parser: (NSData) throws -> T, completionHandler: (() throws -> T) -> Void) | |
(data: NSData?, _: NSURLResponse?, error: NSError?) | |
{ | |
switch (data, error) { | |
case (_, .Some(let error)) where error.isCancelled(): | |
break // Ignore cancellation | |
case (_, .Some(let error)): | |
queue.addOperationWithBlock {completionHandler({ throw error })} | |
case (.Some(let data), _): | |
queue.addOperationWithBlock {completionHandler({ try parser(data) })} | |
default: | |
fatalError("Did not receive an error or data.") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment