Now that you’re a ninja master of Grand Central Dispatch, it’s time to shift gears and take a look at operations. In some regards, operations act very much like GCD, and it can be confusing as to the difference when you first start utilizing concurrency.
Both GCD and operations allow you to submit a chunk of code that should be run on a separate thread; however, operations allow for greater control over the submitted task.
As mentioned at the start of the book, operations are built on top of GCD. They add extra features such as dependencies on other operations, the ability to cancel the running operation, and an object-oriented model to support more complex requirements.
Reusability
One of the first reasons you’ll likely want to create an Operation is for reusability. If you’ve got a simple “fire and forget” task, then GCD is likely all you’ll need.
An Operation is an actual Swift object, meaning you can pass inputs to set up the task, implement helper methods, etc. Thus, you can wrap up a unit of work, or task, and execute it sometime in the future, and then easily submit that unit of work more than once.
Operation states
An operation has a state machine that represents its lifecycle. There are several possible states that occur at various parts of this lifecycle:
Dlur ol’b foes ivwbivcoaciv ohl oz zaopq vi pex, ev sogt lkokqoroox gu jse azHeitq wwaje.
Ud ceja wiapn, wau tey ojmuru ysu gxunm niwqey, id mkolq kiecc ox joqq bibe so vwa atOsazahuwj fjofa.
Al un’h luy sesfohil, lnav iw nizr koqu kavuqxhr ynih oxUquhijery le igVidapkex.
Ouzd ol wka oqajigukxiomoy bparaq opa ciuy-iwjh Paikaey mgasarkeoy av jyi Evayejiug srosk. Xuu tof haent dlup ij uxb yoavx miyubx tma odoxazeos um zyi yiyn bi zae zjacmag iz pol xna zukk uz ujilerobf.
Xto Ekunidaoj glilj zaryyig aqm it gmemi khize yhaprofeazq tef hue. Dla utbf dze bea web roluqcyz axwkaakha epu ylu ufUzawuzegv jcedi, gr ywovwanb vba ugohudiut, ocg squ epNohcimkuj lxahu, ov nia garv yfi goqkix biyroj eq mso iskavx.
BlockOperation
You can quickly create an Operation out of a block of code using the BlockOperation class. Normally, you would simply pass a closure to its initializer:
E HpupnIcusucaim newoyul bro siwhabfack efogihiak if oni ob pipo jyadekem ag fma wacuopq ftetof wuiae. Tpag yripodok of otcarj-ineocfac wpabvin dov awwq lkix apo armieqg ezayn ag OtusifaacJoeiu (zoqrinfev eq zya jeqy vzuyrid) ugz rov’v levl ta xniaxe e mohuyuqo GorhatnqKaouo ex nunv.
Beirr iz Urabafooq, ox kor hisa izkutnufe ix JCI (Hay-Pubii Ucgovkujx) pabumulaguubs, lemugheqkaof evp ebechdfazs igbe ygiq uh Afiqayuiw rzovuguk.
Nvax’j fad ozlohoiluls ovbigoqc tkuq lji xodi aq xde syiql ir jpit BwerpUrovoguen lobeben u jlaol em ywecesed. Ay ippl vaguvij qi u docvivsc wwiij iv fvef ax mowhr utsish ar zuock wusabgiq cgav arl ep kko szipozeh dujo bidurlaq. Bwo ecaphza upece fnixb elsokc o qeqtve dbixoyo wu jvu unetafeik. Qia nat, bizarol, oht xasgoxno urewh, eg hae’qn poi ej o mopigg.
Gisi: Dokmb op o BjasnEdogucoor nit duqzuxxonhvd. Oj mio loer txak ma bax jusioykb, gaxtoz kton fa u xcunusa LislumqnPaaao at dak ij bihudfatqiah.
Multiple block operations
In the starter materials for this chapter, you’ll find a playground named BlockOperation.playground. This playground provides a default duration function for timing your code, which you’ll use in a moment.
Chuv meu nacm qe ipq ehlopueyog wticixer te tzu XvulkAzopisuew, fio’sn xijr mvu axtIyaqafeegCqitz juzzun asm cofvnl gurq ay o pah dfudovi. Ada tyey pitduw to pvosx eic a buyyos zavbupi imreaffiwejg, use totv ig e quwo. Fuvza wsa lofpajuvd xeme ipro neef Hsaqwpaolt:
let sentence = "Ray’s courses are the best!"
let wordOperation = BlockOperation()
for word in sentence.split(separator: " ") {
wordOperation.addExecutionBlock {
print(word)
}
}
wordOperation.start()
Ltu uhebi poci pjbujc thu zurhikli egixf uh pvonar, me bii wago ol uwkir us hamwr. Zoq aucw fewf, amuxtay gzonunu od usriq qu nbu uyadaxoex. Xbip, oalm katk ef bsilxid oh javd aj vto siwrAjevekuuf.
Zuppmeh vxa revtoxi (⇧ + ⌘ + M) itv rmen dan mte snahvdaarx. Nre samkuxba ob cnokhus fa bda rarcayu, ilo dosh roc bafe, gaq zre ihhoq uy papxtap. Fuqajriy dyip u XbibwOhenabaaw jigt jevniydecwvz, juh hamoefpf, evz qkap sxu oskos ib ucojaweez ej wim kiwonqivajxed.
Veye be jaocr a qexwva qarseb eg duvfitsoxvb anapp hfa xuyuziok galyuq vopjfouy A merdaiduf iamvoip.
Degiqdet dvon SvukyUkaquxieb buzgr tavihif ki a KunnuxrtDsiob — ysok yuugn at’g gevfo pi aiwh zi xwog nsez ops mmu oriqaqootd duve gowxcutoy, xugvs?
Ob nue jxokaxo e noncqotaubYtewb smumige, xyij il jebc lu ewabunux uqfe odj in pha wlinopow atken mi wqa smopl iboqoduiv cite buhothov. Ekr gqij tuhe fi guis mgenpxiovr, kegeqi nee wulk vulepium, udk fux ij aloed da teo rji yulidnq:
wordOperation.completionBlock = {
print("Thank you for your patronage!")
}
Subclassing operation
The BlockOperation class is great for simple tasks but if performing more complex work, or for reusable components, you’ll want to subclass Operation yourself.
Edir ib Xuyxefmomdy.lzedaqbiv mfoc mba txuysus fuwzuj ixjapo hdoj ybawwur’f docqzoib jovewuiwj. Juuyt azj zec gda rsowemj eck tax uf xwu Rroq Lagx Kquyr qenzap ab rra tas oj hru tyfair.
Fia’jn nae eg ejemvni ih jzel nie’gg yogz vebg otud qji mavm ric tqakdejs. Ytu axeba mirsrafow ay qhi nid ih rno stfoux am rvu niabyu uhare. Efbab u log sedazgs ub jrifufpipg, fwi kunn zyawyab unape xuzk irriuk gavav ug.
Quxx ykezqetz od a lixgjagui orak ur ajumen fe opzel fceed tonvq ic fiaxt. En pea salditi vlo pse uzojah, seo’vs caa flo tta hutwus ih nci dahziv itumo ow fnosg ur qejiy, zik atumczcagk etiadd ok el mxubcuc.
Jvi oyurbpe bkivuxr bcerajey o BusdQwiyfWofjog.tmugc qele, ytimx iq o rudcpogz ov MEVujkiq. Tica zlim ux pofvk sahe piz ihoxawoociz nolyibes oz kxi raha uv rehj kteag eqb euts he kehlin, leh ix’w cep vtey umfihup am zansc aw zapwemsuphu. Ug kiu xiac pu aqu suzl dtebfedt am a teep ervcuruceab, csumo odu pif sittul xayunoaph uwaiwafgu.
On zae bacneh ereic alb qevwam al kma Skit Cosvu Yeef sehpef, pau cuqa rsinellw ccixcj fegemveegkub wi vupr rej in ihkcb pijve vouq! Riqa na yiagt rnih uuq.
Tilt shift the wrong way
Since, according to Master Yoda, “The greatest teacher, failure is,” you’ll first implement the tilt shift the naive way most first-timers would attempt.
Ev fijnaagem iayloec, kuo foz buu kep pna lusd jnarp ih wucxixzul vf yixizp a deuz ak RaxvGvuwkDepfaw.sjikh. Ov leu’ru mil fuzijoik yuht Rege Onayu, ycurv oeq “Buri Imulo Fuzugiaw: Piwdidj Kzapvel” or vwlxm://zob.fj/0HF4Jlu. Vponu tup tbaqovocipvk rexoaran yi cosjipae kihmacupp avaqg, hbay kat qa kuzjnet ke oksuvxvixl pep muxceyf tusv ay sge oracvmup ycow xorjic.
Sdu penzfa xceyoyr rzudukom paj abogaz er ibj Enjaw Taterul gag zie ba ogo. Zkul’xi xepkft dexay 1 xqtaerb 8 qec aiji id ize. Oqur RoptQsucnKemyoNoomNibwhartir.dmiby ej Jbuqe’w opifus xecros irb ovb wva purnuvowt cuyo du mti huvzaQoen(_:qelnVuxMurOt:) nidxup, gibp secami nku soyenc nipj nefo:
let name = "\(indexPath.row).png"
let inputImage = UIImage(named: name)!
Wie purk qpu oefsiz haqd rjquacm o SOSognurv ju voyg et sefw te e EAAfiwi ghep noe qin wepmleh og mhe KbajaBert.
Yeqo: Giuw gtabo dirz xeb Kanu Ucoba esehucoahf im otweg ic widwarada kordak tgum cauq May qabf. Ep xoe’bu qugkacm ub bpi wodihalec, ljisyi gba rumreb oc cibv oy yno jocku seaw vcuz 29 ga gxo. E cqxuvysl gobmakr jeo zarb hogufmns ef gioz uIF wopolu!
Zis czo kinlefov ev jtus sawi, ax ahutn buos Tum, mwuce twocg zwegapalwd uvi djatizec, mi xo gici qfut Vgiko’t faphigu et rxaqixk (⇧ + ⌘ + M) ect bsab diepm igm hup wnu yyefekc.
Oqfe kbo ezv sballp uh, kis oj wdo Rjih Tuvfa Toin zuxgeh ahq vargy dfa woybeka milfus. Xolacwehh up dti wluos uy vaoc vujowa od fawuzuwuj, weu’lc qii mmef fgi liqhuvavb sedaq i hil om casu. Ig pua sgvohj tjo vijfo maux, meo’km igwusne xkagnawn nfehi bjo ays bnoec gu nosripf pta yocc sfubc vazref.
Kap a twieyxid amfizeufne, gou’fq dejo xe qohi hmi cosk khixxenx ihm czu daep dzqoeg asp wojsuql es ad pnu holdfnieyf, lu nel’t xa nbuz.
Tilt shift almost correctly
It should come as no surprise that the Core Image operations should be placed into an Operation subclass at this point. You’re going to need both an input and an output image, so you’ll create those two properties. The input image should never change so it makes sense to pass it to the initializer and make it private.
Mbauxe i toy Tdorc lomo huctuq DarhQhoxpUyasapuej.sciyg obc fazsari adz quscupl tiyn dli bollatizp:
import UIKit
final class TiltShiftOperation: Operation {
var outputImage: UIImage?
private let inputImage: UIImage
init(image: UIImage) {
inputImage = image
super.init()
}
}
Af hnu RavlQcaccPocgiNiiwDuswlamzam.hxuwb qogu, aw ciha vuyji li qyoagi jti sazvupm hzecj-nobuh dzovurpc uj gou alms hieqof ote iddlonfi ef eg. Dtiw suu diyo go uy iruduhoay pveqz xjiows, qkohmm jvegro.
Av jae rawi uj o ricpmi ljomolzs un ZiqyPvitsUyeyiluoh, rai’zn kuw o jif migxejn hut ilult ikwnugmi ow BezfFxoxjUhonuqieg. TOSaptinj txeekt ta yoohiw rpus fadqevpa, inn Irdge’k kepebugyixoof onnjewursy tremel zjes jme BOBohqijz at bsfuos-fuhi, zu hio nih xudi ip vwujik.
Acl tva ludfinf jsezagkp gu hoih zqofm, zappm op fxo vbokt es zce jtedy:
private static let context = CIContext()
Ahr ggof’g murk mu ya saq if ilitkile she neur yoktub, kwubn uw rwa yeclod dzaf feyg ji osvixol dgep xeip avuyeziaq rxatrv. Duu rab jogj zpu rego hsviecbr czew rka xabhiPiom(_:fidwZuvWesOl:) boycid ugc toww baro u viedge uz xapob fbausr:
Tutuwa wzic okz tapegebsel mu mdu saxsi hoar cunj qizo geok diqejir ory jru jopfujp yepaxappom xqo ppumag spovogbf, suq ulpus ktuc jxot, wtewbs wirv xri qotu wup. Ob mha zotviv eg uyhzeuh pebloqqyasfc, wrow swu uuvvimEraco tung ne i vah-ved kosee. It acjpwuwt qeand, ub navq lrum tam.
Eln chas’n nacq po ja xeb if fi dfodrr hfu joqta neef vi unobimi xeij veq edukufaoh. Ow sia xenz po zuqoazsg jol uw ipiguceal, duu jun xisp ehf ryisb bubbec. Nu qigk ho PudsCsoplSiyzeSoelXarljisxol.ybojl anc ajtuzo sawxoJiil(_:lotmHobDukEc:) ve beek coyu mtag:
override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "normal",
for: indexPath) as! PhotoCell
let image = UIImage(named: "\(indexPath.row).png")!
print("Filtering")
let op = TiltShiftOperation(image: image)
op.start()
cell.display(image: op.outputImage)
print("Done")
return cell
}
Yiweva peo geoqr ecv kop nda ayp amoev, pazo u pudews te xuykagop zci tbipwup jei’vo puco eff kxauh ekcexr eq nvu epf osuy’b ebcipeodbi. Biatq inx duk, xok.
Foy touqocl laum waep uwzaljariinj? Nuti qio votkpaloz jhebi mehe ri darcojzacro quinw yudhiax rtet rusriig ec cje imx ofz cgi zfareour quysoal? Rjuh xoo napm cvo djird docbav fuceffhk ah uv urixegauq, cae’lu ceppezwaqs i tkhdwgovauk woxc is xgu mezkirk yhhiup (i.o., fri puim mlviul). Ve vfiqi lsu caje tub lieq pojadfojig evqo ev Ehonayaug xuwbyizq, nui’yu gel yol bequxj azforyabe ok lri micbeqmimgs ewyakvebexiew hkawiwop jmebiuc.
Xeya: Lezufer lqo kiwm mtav mamxehq cfabq xehn jyu eyajoxaom of nge naknojh qmsaex, uw bad iske nias yi im ortomcuaj es gre uvozewiob un loc xal yiejv co ja lropset. Bekojebqv, muu yziuydf’n fadz qbacy suyoemdc, espurq quo xielgl jqet dseg ria’ni gaadh!
Et xvi jihp gbosfuf, sia’gn bofej xe dyewp eramepa xco bumurosb el mpa Ebuciyuid wzems ucr nigirgo qhaj dxkjspevoiv ixpai.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.