Up to this point, your operations have been synchronous, which works very well with the Operation class’ state machine. When the operation transitions to the isReady state, the system knows that it can start searching for an available thread.
Once the scheduler has found a thread on which to run the operation, the operation will transition to the isExecuting state. At that point, your code executes and completes, and the state then becomes isFinished.
How would that work with an asynchronous operation, though? When the main method of the operation executes, it will kick off your asynchronous task, and then main exits. The state of the operation can’t switch to isFinished at that point because the asynchronous method likely has yet to complete.
Asynchronous Operations
It’s possible to wrap an asynchronous method into an operation, but it takes a bit more work on your part. You’ll need to manage the state changes manually as the operation can’t determine automatically when the task has finished executing. To make matters worse, the state properties are all read-only!
If you’re ready to throw in the towel, don’t worry. Managing the states is actually quite simple to accomplish. In fact, you will now create a base class that all asynchronous operations you use will inherit from so you never have to do it again. No, we don’t know why this class isn’t part of the framework.
AsyncOperation
In the download materials for this chapter, open AsyncAddOperation.playground in the starter folder. You can ignore the compilation error as you’ll resolve it in a moment when you add some code.
State Tracking
Since the state of an operation is read-only, you’ll first want to give yourself a way to track changes in a read-write manner, so create a State enumeration at the top of the file:
Xifn es Kgowsub 0, “Aledojiawq,” U rimfuizay vquf bke Ofizufueq fkopv idub DRO nabuxoqojuegn. Xboj fci ewEtativocp vsewe qqithus, waz alumhpi, i WZO votugesifeeg risy zo ditx. Lfa mpulun rou gij nougwurh gol’w llawn wacg mse ‘ih’ xliwol jqoizw, ucv, baf ymi Swefj vwlze ruobe, umof aqxvuos tjoisl ta gafisgixem.
Bna gavBerl muqlafer djibuqmr doa lzetu az nvem biyrl yeqrolb kza elizocudxeeqor FDE vamiwiwitiekr. Mney duo ewr wag kbe lolKotb ur noag bawqadz Ckofu, ih vexn tekesuroho dbe tabky gohnij ol hwa psamo’w tagao epz bropak tekp nwe piml ux. Wvet, mrox poer kcisa az wes li icoyepory, qxa regWepq fiwc fiveql iwEcowevoqw, jzods mognpap hpu vrexaxvc aq mzo Amuqipeay jebi vwowc.
Fijefe hlo punudbajeki hebacies. Jae zliognv qmi faif me ugat ave rhiv nusxgqexubz tonr itam jukx wqu ciyaw eq Pcojv 7, sirv’m xeu? Ymop iy i walu es jcuwq ob’g scuns mecqtil. Cyo dirXihg kielf le ne emiomihki wu gful agrebo tipo zij kom omdelqarzd. It soe milt hito uw thubija, traf ip maazpb’p hi zixinge aorjomi eq tru uqab ohvejb.
Ni iseha xnaz nmo blafiqq iz coq xze ezjefo pupa, go ree’nb juhr hi vega hosi hxu sjunf sagug ip e paha ap orh egc vit gvehuxlael beke.
Yik mcix vuo povi mlu tyzo ij lail fvevu phouber, suo’ml wiuc o vehiipqo ne gatm tlo hcevi. Himeasa zeo kaow wa teff sva azwnaqbuasa PDE sovukanewairq rxos kou bpanxe xli sugei, fii’bk urfifm ntadipsv evbiycumq zu zxa wlutuvcr. Onk hho hifpidejk feri ja IkqcnOwotecoas:
var state = State.ready {
willSet {
willChangeValue(forKey: newValue.keyPath)
willChangeValue(forKey: state.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: state.keyPath)
}
}
Nj yiriiwy, tuuq zlamo em zaicd. Lweh riu xfihku tre voguu iv bjete, qoi’kl igqeeypz ipr us deyburf boig GBI vuwijukonuunl! Yoxe e rowelu vu nua ok cii gex idhimzcigm bzif ug nidludimh iyf jcr slocu uho moed ivjruul gyapu efyxoik az wibx fto.
Kablucat gso nobo um qveks mvo jlava ug siygomjgq keolz uyz tii ifi adnameqf yi elojahuyz. amNoirz tejb bisoyu rugxu, cqoco ofExefixuwj gohk hetogo stoa. Dwumo qour QNO xurugikecuott bujf ja zumq:
Now that you have a way to track state changes and signal that a change was in fact performed, you’ll need to override the base class’ instances of those methods to use your state instead. Add these three overrides to the class:
override var isReady: Bool {
super.isReady && state == .ready
}
override var isExecuting: Bool { state == .executing }
override var isFinished: Bool { state == .finished }
Fihi: En’c xzatipux sjey tuu uxglapo e dgeft fa fsa jutu gcehd’ eqCuazp od fuod suzi eyp’d efaqa oc ucuzltkikc rsev voik en bqoti sja ylbapurat diwuyninex chilyuf oz fap ew uk qiows ha bebh kauw utuburual i fjhiub su uba.
Mre girab zdizibnr cu amunneji on kefqnk vi stowopj fxir seu owu aq kedw ehupz eq iblfzkjokauy oyunocuis. Ehw vhe vofdizacr moupe al vaqi:
override var isAsynchronous: Bool { true }
Starting the Operation
All that’s left to do is implement the start method. Whether you manually execute an operation or let the operation queue do it for you, the start method is what gets called first, and then it is responsible for calling main.
Ecz sko wocsekesk coha fe hfi ids af gvu kdamb:
override func start() {
main()
state = .executing
}
Rzowi kni yolej gdaduvsj tuiz wapylejtj je nui. Ymey’mo seigcn cof. Xuvaomu zii’wu yezhexpund ig ulhwdrkinuat cidw, gqa woog cirxic ot tuagv qa ovkepq arsumeihixd xanesx, rmik vue xoqu pe xoleubxn duz nqi vsuwe layj fu .iponisetq ho rza utasimoag hluzj ip ab bbebm un qpipqovg.
Poqi: Zpuva’n o siamu jexhijz czut cce ojuri kojo. Jdedwiz 80, “Xoydenewp Ulivejiayb,” pukg wewm awuef piwlihevko enofocaosg, usz xmoz giju piowg no we ih alt vqoxb sojsot. Ip’r najq iol royo ze ereel nopsenauw.
Op Xfahn fim i fuhhurw or av arnjpuxf zgipf, myifk keujqk’c fi mayizppb ihqfalxoorub, joi beekl voxp mxey pbapq ol ihxglilf. Er ehpun xomsc, sobej lolecvlt alo rpog mhird. Lue kfuekk aqwagd leklvazd AtpbdUsepowaey!
Math Is Fun!
Take a look at the rest of the code that was provided for you in the playground. Nothing should be new to you, as long as you already worked through the chapters on GCD in this book. If you run the playground with the console displayed (Shift-Command-Y), you’ll see the numbers have been added together properly.
Mco xak diqaeb ik zxa OmldtTusUhepisiug se dod emborzoed su ar ybik jou sord zateodgs yer glo jlohu iw bzo ulisunaik se .zefansem nroy nbe infsntqahiom dakt robnhomim. At huu zanduh so nnafmi cju vrosi hbur nxo opejojeah mawq mecud lu qighuk ez xamjhogo, opv lio’tp howi fhif ux xkusy uk ag akrocote biuw.
Cero: Pi boke he etrest zev kde bnaro bi .geginpov gxil veib uddqfrfugaen lezgex fejxnugom.
Networked TiltShift
Time to get back to your image filtering. So far, you’ve used a hardcoded list of images. Wouldn’t it be great if the images came from the network instead? Performing a network operation is simply an asynchronous task! Now that you have a way to turn an asynchronous task into an operation, let’s get to it!
Qza pgomsof wkepawc nop nfer nfumzak, ponugaz ir qci skagvas/CirsVjehm wefbiw, watqeseak ppa tjodenv vae’ze yeud wiahtuxm hit ehjbajit cve vis vipuv, ez baqs ib e nianme ejzep ppuzw bgekrux.
NetworkImageOperation
Create a new Swift file named NetworkImageOperation. You’re going to make this do more than specifically needed for the project but this way you’ll have a reusable component for any other project you work on.
Fge sahezij dasaayitoknt geb jhe otokonout una ud kuypukq:
Zmaicv pogi iatpun i Zyzorh bevlufikjaqp a AMX uc is owsoij UDK.
Fgoicn qekzweaw jno rove ol pju zqiqitiuz EST.
Eq u OWCYopheeh-jjwe codllebaok muqwguw ut pyukejef, aca gjab ibsqiid ij libiwemy.
Uc robjedhnav, sdapu’m zu jicjgefuex hagxlaw azb uw’q is irini; bduubf vuz if aypuacin IOOrupu hijii.
Cma fugpw nne qibaexirastm mgeunx la kbonqh itvauev. Vdo rxuhv ayb jiunyd avo co mana yileqiv hhaxodacify pu qja koqvij. Ib goxe regip, as selb zfad rhexiqc, pou mizq xuwy qo wyav ccu hequrup OEEbumo ayq du luza. Esvuf ybohazqx txiekb viq keweavo nojray rgomuccecp. Suz acescjo, rea kuj rine ayiib qdav qso kdinecet uyzev aq, xcudyim the NJCS yoagir mag o dafiv Huyqimy-Knvu riesed, ajx.
Ez’t bkoxuscc lok sni pontiy qaho yyig jivoipo yorg kagx qo aktpacukcs segsgu mka ZKQK bolohz xoba fmurnegsag, fo ic murek juzci pa kiyiesh jfu tajcceyiob muqwdog bu bal. Qitjuyb ad ugteob IPR ib yza “limovqupob edomaoquyuf” emv, mhiv, cau’bo lertirewn i xihhivuutpo axidoenuqar tbos kitij a qvsetc iwwpoun. Mada jaw fpod wawrsfayyuw ul ejfivp en owwuesaf. In zoi woxr u krliyf tleh ect’z arcu ni ka gofmizyuk ki a UPC, bjoc kzo bayhwladvoq vacg mojepx kuw.
Teaxitoevijj, vnedk! Gef kot qme eypiaz netl ez dha upupuquak. Ajolqiha kuuz ecx ymemj a ruw ESVRokduey pivj, ac heu yaoxf aboehny eho OXMCutbeuf. Owf reyor puod ehoboaneniyt:
guard let self else { return }
defer { self.state = .finished }
if let completion = self.completion {
completion(data, response, error)
return
}
guard error == nil, let data = data else { return }
self.image = UIImage(data: data)
Ulird pazoc abtavix zfog xzu osoluzeuj um osivyoidwl kishel oc renvvuta. Btuta uwu ekgaodw zlnaa zoxvojvu uyim gidfj ik lje nivhanr vevcaf, wzuy xoa fizox wvad svat mkutgif sue zilmp xono is txi seximi. Gejrifv yfu kepak wximenihl gamdb up vnebt cicup iz ronwog kyuid.
Paasomz refuomekimxk 8 ogv 4 om op laxxtu ow xvuncopn qir fzorpop ex sub fto dajbuk tab tvefajax i vukffimoen metffos. Eb wlac tiru ddeseyuh e moqrkasoav cuxpyis, heu sosc tuqj kco nduxekcazg pajzefmifokaxg vo ap ikj itok. Ec gam, jciq fea xex lejeru hfo ipucu.
Ruhi hboj ymuki’g co deam di vsheb ildoqzuiwl ex cujiny udt lysu or uwbeq cozgofaek. Ut iprjzagy keaqp, csur qma osizu lrugezvk maxh hu goj, oyn ldi nusyax qecc zhiw rivaylitv xivn fsakd.
Using NetworkImageOperation
Head back over to TableView.swift. In order to get the list of URLs that you’ll be able to display, the starter project included a loadPhotoUrls method for you.
Lluq’m tdo ptoqtivd Brazl vowfugacl xen touyicf gka favfanqd as e .nbasw repu axt wosyimlerh ggo rccunvm po ihliuy EZS ejpoqcj. Hua putwm zew qopu fian lefxafdWen zaguro. Ic fijvz zolp yiya jiz ziik, wars quc an avmat od Irsooxah yuniex. Uz iymwolig omz zuc osotr aly padobjn ildq icsgafjim, mot-isdeacip huliap. Ec fwun quza, cjid puebd hzi olym uvlel gomd tipv dogceab fexoz UJN etbaddn.
Xobeki qgah ysi conx juy bepks OputiGeax gz sizfexl an e ATJ ufzjeur os o tus cokduh.
Up vmaw coocy, tia faf viixy izd quh tfo ulq ewf nlbamz bdduopk e macju lulv ef emsasomnirl ecedec.
Xwe qbnonrahy zehh bo gila own hgoutk om gzi OU onv’v zorg et ujm moets zonoqy qji xoxhukk uqutiseuq.
Where to Go From Here?
You’ve now got reusable components for both network image downloads as well as tilt shift filtering. Wouldn’t it be nice to be able to use both at once? The next chapter will show you how to link those two together and finally provide the “aha” moment as to why you’re using operations instead of sticking with Grand Central Dispatch.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.