ios - Interdependent NSURLSession tasks with NSOperation and NSOperationQueue (Swift) -
problem: develop ios app in swift perfoming initial load right after login. sequence (of rest based calls via nsurlsession) this:
- login user account -> asynchronous response returns userid
- get countries userid -> asynchronous response returns countryid's
- get products countryid -> ...etc...
basically find elegant way on how implement such sequence.
approach: first started calling new (dependent) rest call in completion handler of another. if many calls need executed , dependency levels more one's described above code looks little bit messy...
i came accross wwdc 2015 session on nsoperations , thought might idea can define dependencies easy. unfortunately sample code provided apple not give answer problem described above...is (and did not it?)? while playing around operations not make mind on how solve initialization problem @ time creating different operations (loginoperation, countryoperation (dependent on loginoperation), productoperation (dependent on countryoperation), etc..)
i found these posts helpful, stil i'm lacking of understanding how approch best problem described: how download multiple files sequentially using nsurlsession downloadtask in swift chaining nsoperation
: pass result operation next one nsurlsession nsblockoperation , queues
difficulties: initializing operation b @ time when operation finished , has returned result going used operation b.
if still relevant, may have answer.
the problem here you’re trying defer initialization until first operation finished. that’s dead end. operations meant created early, , order guaranteed using dependencies.
so let’s discuss approaches extremely frequent problem.
(you can note examples written in wwdc-session style. because use operations library based on talk. take @ if you’re interested in operations-based architecture.)
1. use external mutable shared state (cocoa-way)
that means that, example, have usercontroller
, instance of you’re passing both loginoperation
, countryoperation
. loginoperation
writes userid
controller, , countryoperation
reads that:
class usercontroller { var userid: string? } class loginoperation: operation { let usercontroller: usercontroller init(usercontroller: usercontroller) { self.usercontroller = usercontroller } override func execute() { // networking stuff usercontroller.userid = receiveduserid finish() } } class countryoperation: operation { let usercontroller: usercontroller init(usercontroller: usercontroller) { self.usercontroller = usercontroller } override func execute() { let userid = usercontroller.userid // continue } }
and then:
let queue = operationqueue() let usercontroller = usercontroller() let login = loginoperation(usercontroller: usercontroller) let country = countryoperation(usercontroller: usercontroller) country.adddependency(login) queue.addoperation(login) queue.addoperation(country)
the problem solution it’s pretty complex , incredibly hard test. , swift doesn’t mutable shared state much.
2. initialize operations functions instead of values (swifty-way)
well, not obvious amazingly elegant solution. saw, values copied on initialization time. need retrieve needed value on execution time (as previous example), without such tight coupling. well, can done - pass function initializer!
class loginoperation: operation { private(set) var userid: string? override func execute() { // networking stuff let receiveduserid = "1" userid = receiveduserid finish() } } class countryoperation: operation { private let getuserid: () -> string init(getuserid: () -> string) { self.getuserid = getuserid } override func execute() { /* because operation depends on `loginoperation`, `getuserid()` called after `loginoperation` finished. */ let userid = self.getuserid() // continue } }
and then:
let queue = operationqueue() let login = loginoperation() // force-unwrap no good, of course, example it's ok let country = countryoperation(getuserid: { login.userid! }) country.adddependency(login) queue.addoperation(login) queue.addoperation(country)
as see, no tight coupling, no shared mutable state (countryoperation
can read, not write — good). , it’s ridiculously easy test: pass whatever want countryoperation
initializer, don’t need loginoperation
@ test it!
with approach, actually, main goal of nsoperation
achieved: distinctive, abstract pieces of work. countryoperation
doesn’t know loginoperation
, nor other shared instance.
i use approach lot in projects , works amazingly.
please reply if have further questions :)
Comments
Post a Comment