swift - How to avoid having a pipeline of functions? -
i in process of writing code following things:
- sends request web service starts compressing database .zip file
- repeatedly invokes web service function checking whether database has been compressed , ready download
- downloads database using nsurlsessiondownloadtask
- unzips file , stores documents directory
- renames unzipped file desired name
besides that, entire process takes care of error handling using callbacks i.e. closures.
the far code follows:
func continuebyrepeatedlycheckingdatabasezipready() -> void { let conditionclosure : ((x : string) -> bool) = {x in x == "ok"} let repetitionclosure : ((x : string) -> string) = {result in string(result)} requesttask(method: databasezipready()).apply(5, c: conditionclosure, f:repetitionclosure, onsuccess: {success in self.startdownloaddatabase() }, onfailure: {error in self.failure(error: error) }) } func startdownloaddatabase() -> void { let databasesourceurl : nsurl = requestdatabaseurlfordownload().requesturl downloadtask(url: databasesourceurl, progresscallback: {received, total in }, successcallback: {location in self.unzippingdatabasefile(location) }, failurecallback: {error in self.failure(error: error) }).resume() } func unzippingdatabasefile(location : nsurl) { unzip(sourceurl: location, destinationurl: filemanagement().documentsdirectory()).execute({ self.renamedatabasenameintocrmdb() self.deletetemporalydatabasefileontheserver() }, onfailure: {error in self.failure(error: error) }) } and forth...
however, want avoid (for sake of code testability , simplicity) having pipeline of functions such. first step, i've taken @ gof , tried find pattern suit problem. but, unfortunately none of them fit problem.
therefore, have piece of advice onto how break out dependencies between these functions i.e. behaviour? keep in mind i'm trying have code functional possible.
a couple of observations.
you can remove code calls next step in process these methods , change these methods take completion handlers. then, code calls these methods trigger next step.
func continuebyrepeatedlycheckingdatabasezipready(completionhandler: (bool)->()) -> void { let conditionclosure : ((x : string) -> bool) = {x in x == "ok"} let repetitionclosure : ((x : string) -> string) = {result in string(result)} requesttask(method: databasezipready()).apply(5, c: conditionclosure, f:repetitionclosure, onsuccess: {success in completionhandler(success) }, onfailure: {error in self.failure(error: error) }) } func startdownloaddatabase(completionhandler: (nsurl)->()) -> void { let databasesourceurl : nsurl = requestdatabaseurlfordownload().requesturl downloadtask(url: databasesourceurl, progresscallback: {received, total in }, successcallback: {location in completionhandler(location) }, failurecallback: {error in self.failure(error: error) }).resume() } func unzippingdatabasefile(location : nsurl, completionhandler: ()->()) { unzip(sourceurl: location, destinationurl: filemanagement().documentsdirectory()).execute({ completionhandler() }, onfailure: {error in self.failure(error: error) }) }by pulling code determines next step, can unit test these methods without incurring dependencies , without having stubbing.
in terms of how initiate next step in process, can call each in completion handler of prior one:
func runwholeprocess() { continuebyrepeatedlycheckingdatabasezipready() { success in self.startdownloaddatabase() { location in self.unzippingdatabasefile(location) { self.renamedatabasenameintocrmdb() self.deletetemporalydatabasefileontheserver() } } } }if don't nesting, there lots of ways establish dependencies between asynchronous tasks.
you can, example, wrap them in asynchronous
nsoperationsubclass objects, , can use dependencies between them.or, if you're ok third party libraries, can use promises/futures library (such promisekit, brightfutures, or rxpromise) in can chain series of asynchronous tasks together. conflicted on promises/futures in swift: idea, i'm wary of these libraries due inconsistency between them, lack of wide-spread acceptance of futures/promises in general in swift, etc. mention sake of completeness.
i must confess don't relying on self.failure in these various methods, variety of reasons. i'd have completion blocks called upon success or failure, passing along relevant information, , retire self.failure. want make sure these methods not relying on properties of class, rather pass relevant information each requires other.
Comments
Post a Comment