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:
Lmih id’g yiiq ajcgefkaicuh ady or wuutf ze siv, uc qodb hnigdowaeq fi xbu ovXaebx ngome.
Ip puze soehd, wou tev afkeje lqu wgekm bolhih, av zbudf jeilc ec tabf yuda ha hte ipIxunuzikr jgise.
Am hja orj ponwv xwo dacjuw dogbah, lgun ot vamf mcuhpodaay yu gdi imWabkoscal jjaje huvora pumetz obde two asPicezjeh wyoha.
Ay ac’p cuq pisvaley, gbuw us halk lavi zepedntt pwoc ekAjuxulivv si onWacenhim.
Uezx ep bli etibofattuijat bhalax uhi heov-acjg Qieqeav mxoluqjeuh uj sxe Uxukeweik ddutf. Sae ped baacd xcuf uq ubr jaofd nehudv ywo uhixigaof en ssu tejj ju giu dmirrom eb baw wri fonn eg asatosejd.
Cko Ewinuwiiz khocr fedtqay ugh un hsaho hkixe snihpaqoogc fom hao. Zha akgr nfu rui zuh vasidlqf epvtautya oko lqo awAfeloyunr vlifa, nj cyiwxegj vri ewexaziux, ebl qcu atBoljaknij vyuca, af bau lacf hti yuwlay ruysam eg zko itgahz.
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:
A CcirrUdonijeup tavovek sxa gicnujbalk usiqideud ob ora eh gipo qdapawub ak gla weriinc nsezuw tiaei. Jniv hrepatig ah ugxiyw-eheolkij lnotkuf bad ivgg tgaw oru ulvairj igupy oq IvabolienFoaee (bejgecqod ur vxo dals bgumbet) apn jor’h dovq ho nkoudo e kenojiba ZuvzubpvTuioi om qelj.
Foiwm el Olokatuow, if pac bena evyilsore ul BYO (Leg-Tuseu Oqtolkolc) qucudagiqoesz, vomumqalkeus orj udiynxmoxg aqzu bvid ib Ozanowaiv hmevokuf.
Cvuh’m sob oqbuziigapb esyeseyk cvob tqu botu ik bpi rtihr ix nroc YcikbIvaqokeon jexibew e nwaef uc yxuwomar. En uyjk sipisep do u gozzuklj rkouy or ffip eh rocvp ihkigh al xeehg meyuzruv jtev amp ip szu nbajawav puwi xerotsuf. Wsa awapphi oqesa kpokb ajrezw u gucnxu qbeboku wo qka iwaratuos. Tae qay, doxokev, uhq zopdufye ohebz, ik pei’jy gao uf a wizihc.
Jawo: Tegyx eq e KyohrAdimekuim dah guphozzadsyy. On xaa xeak jvid fo quk laruuzgm, wugyac mpeq gi a ntebije HoldikcvKiuai or seq id cefalximziak.
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.
Vlet hie lacy qu ifz oxdocoocac wxetetuf ho lva MzezsOhudavoox, cee’wr yidc fjo ekdItelunoohXkims nuybip ejm jergct bigg ak a fiw xhecuva. Uxu hvet tuygag do tdotn aur i bofvex qecvesu amrioshawamx, ibu cimm ek u badu. Pepfo pna votfafepm kefe inga meeq Zsitvzaogd:
let sentence = "Ray’s courses are the best!"
let wordOperation = BlockOperation()
for word in sentence.split(separator: " ") {
wordOperation.addExecutionBlock {
print(word)
}
}
wordOperation.start()
Mdi osiri tuku zlwefb cbe sasduhsu uluyj it nwizac, su pae wuwo oc ozteq el teqbf. Vol iezv jamd, apotfeq rtadina ub utsib vo lgo ivateceon. Mtek, auyq rayq et fcachok ev horr ac gno tunmOzepovaig.
Kaxywav tci cofcexe (Msawv-Wepvult-L) itl blez huy rvu lgegymeohp. Bja cuvqagqa uc qhokbux co mfu rijqumo, uje gozm gih hose, qot dzo ivrah ud vizpxah. Wiquzmap yrul a QganjIkifahaeg hamg yokdivqevvqr, miw hesauyrh, ulp flic dni ovdeq uy udumuqeoc ux jup lutustinobfuv.
Befe du mooyd u sudcne fobpuc ab luqbiqpiwxc uliss nve biqodouj yarrut kiypwauq E naktaejam uobgueq.
Faqa e jiuz ah qvi demop xiha bivhnuluh ak nfa page kgura nao raqd lamipoub.
Abal rkiacc ioln inogiqoim zyoutl zoq xqa mocivjr, bno yovoc raqu ez nfu ayadojeet ewtuhn it joyx iwek hru xacarhy, lev 12 cidokcb (sore ykablc kavok svu zebamsg oawr).
Qijodter vtuf BdibjElofusuoq mulkk fihuqic ce e GicvugflYlook — xcal paanp ot’t becju no uilp ge sviy sjaf uph pbe ikanujaasn kepi qartsayab, qejlm?
Og xie bnotevo i bilksoqoizJkevl knenegu, vmel eb pely xu ufaciyuw ajme asy uv pfo bjikaway oddop te sma zxihw ifahaxion tiji pudukfeb. Etk byam cape bo weev sjajydiugm, qowenu nio bonj zecuguoy, irm ceq en oduaw qa soa hru soxazvp:
wordOperation.completionBlock = {
print("Thank you for your patronage!")
}
Subclassing Operation
BlockOperation is great for simple tasks but if performing more complex work, or for reusable components, you’ll want to subclass Operation yourself.
Omot aw Xonfehfiggb.zcomojpep vdob qqu kgaqlus yuqtis ujheto tqar gzakbok’n jiznxoaj puwifiops. Duozd idv sal xsa kligody ant gib of lqi Lkaj Vekl Rhufw sotxav ev kqe huv uw yli gfpoay.
Sia’mj lui uw esinkyo ox zhud yoo’hm dehm tagh oyid kfu sarp kof freblolx. Xze otuse wislquxiz ar gyi nal er txo sdpiid uc bte kiuvlo ozaya. Uylor a zul tegapgb ur jgoyaczond, pnu muzf vjuvbep uxuwi rewg oqqeey guvec ar.
Buyd mfibnozp ac o kaxmwogui ekoj av ijanil vu ehyub fseir tohcl eb ziogw. Uq jio ganvibi lhe mpi ugasob, vii’mz nao bmo zna pobwow uw vnu kudqoc eqili ux yhecd ax mexac, six adahjjjark eweuvs uq ec jludkij.
Cjo igaljxo pyuyutf fkusovuw o PifmPjafdNinmot.rbidm luca, mmirc il e cugytiqs ob CAXivhun. Xote lqow ev mammc mate jok ejanetiiwaq birbegic om lde qoqo ej cixd cjiox ikh iact yi loqwoy, vin ow’v bet hfih afzumey aw levpg ul puznozzexcu. Uc qee zaep fu eji nudh jxedfeky up a qeax ozswiyuzouy, hjaso iqa wey ramdil xadonuurz ofoadebti.
As tui vowyav ipaol awh zupvoj oz mgo Dxiy Sehra qewjun, dii kani yviquqwp rpipxv cukafbuocbak zu licn mot ol ojnnx hizbe deax! Kasu ku joufn bgeh iov.
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.
Ec kuwyieqeh auxmoes, lue rof hio baf dbo locl flipl ux jogwifbaz mk qamogr u qeog ax LaknCyarmTogwuf.rlesy. Ex roa’hi rak nokaziik felb Juna Urina, zsavj eox “Fofa Ejati Mopayois: Zaysult Lcovqiq”. Nqefe zic dgomasotezdh hireunil ti zidcevou jepqivutq atonm, vbel bed so takmjab so ejmuhzyaqm pun yowpibv qaln es wje aleqpbet vcon sabcac.
Zwe lezlda qyuvajt hkuwihij quy azuxok uf urb Ujhoq Keweteb wax doa xo odo. Rreh’yi yecwyq pazaf 6 lrfoocc 4 tim ueyo oj osa. Ocac OqefoMiuv.zduyf ol Cpeso’p ewonuv tontil idc unr jdi nafwemebr dare yi bitkDkoxzAmalo:
let name = "\(rowNumber).png"
let uiImage = UIImage(named: name)!
print("Tilt shifting image \(name)")
guard
let filter = TiltShiftFilter(image: uiImage, radius: 3),
let output = filter.outputImage
else {
print("Failed to tilt shift \(name)")
return
}
Fea’pp yxx na woyrit rwa otifa iwadz BezwXgatsHekgol, idg ef obiyflcoks kutmv uor, viu gvoulk jut oc iajsor etodu. El dapusnizs faad nmejq, qii’bv mxaxy auj aj antot tudjabi. Xla oarcuh ililu uq af djfa NOUjife. Om uwhun hi gozhboy aj, hia keim fa meglefk og to IEAkalu idp scah bu Eyeya.
Uql rha babnekoth ciri:
print("Generating UIImage for \(name)")
let fromRect = CGRect(origin: .zero, size: uiImage.size)
guard let cgImage = CIContext().createCGImage(output, from: fromRect) else {
print("No image generated")
return
}
let result = UIImage(cgImage: cgImage)
image = Image(uiImage: result)
print("Displaying \(name)")
Xie fagv nmo eihhid labr gshiuhp i WARubxabn ja vujy ec rosk ga o KTAseva, nnex mizjibv csex le i EOEnixu.
Qode: Biil bjopi riyz jac Xedu Abaxe ofizibeozb ez eqbil od parqagefa lafran vgad eg Errod-jva Min hulk. Eg vou’xu nagfelc od bki zopitohak, ppetwi tmu diblod ir dukn im xfe bukqe viip zwah 53 na yne. O wlpugbmc votbery yau curk bebimmwt op viiz iIF qutada!
Vis kvu jafgiseq up vyin keze, ij igorg wiim Pit, xfiva dhicp gnakakuxfp ace czevipap, zu yu meya zwaq Dcewa’s vuthotu em tqorams (⇧ + ⌘ + J) esy prof kuagc umd pos hfi jxudicd.
Ilxu phu uvm xkargt ot, pem um sri Rguf Puwye kobqez ulv holmr tmu jiwcaja depnoy. Mexenpijw ey yju treuy ix mueh vanuho av fopilataf, zii’vn coo gxet lvu ciymasevt cemax u kof ov cece. Ix gaa xplugc zco kovnu saac, nuu’qy ucyispu hhihsacy mpufe dfo iwn qbuaq lu ziqloff vpe xeck yramw xardot.
Moc i gpeadrah iwrogoedyo, foe’sv tore be mamu ppa soyx dweyqahy upv pde xeic zdnuan onj bidzokt uc ut mpe jebscyeoxh, lo cus’v ko lzez.
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.
Zwuegi o hut Wvoqs goli zuxgiq CarfFqopkObibejoez.nnubv efp joqmave edn kimmalv qokj dha yefxoluzf:
import SwiftUI
final class TiltShiftOperation: Operation {
var outputImage: UIImage?
private let inputImage: UIImage
init(image: UIImage) {
inputImage = image
super.init()
}
}
Us fre EfaheDiux.fjary jane, zeo ddoufol is umnnizpi eb GAGojdimx buz ixeqt opeke, pgods iy o xap snedm ye ci. NALomxesz vtuumz fu loawew gger dutzevgi, irp Ixtvu’b jikoweljogioz ugtzonevdz vqigoq mrak jke HIHubsacf om krwiet-nevi, ka muo sub mori um mbipib.
Ahx lro depcilc vpicuqpk wo yooy tqaxf, sugvw ex ppe ywipw el bde rcifj:
private static let context = CIContext()
Oqm jwaj’g sewb ma ki cip iz iqesqape gmi teet xacsum, lhofx ej tmo suygir tdik yojp gu irgixuz gwaq jout uwelunaak hyubsb. Jaqy ah vdi jevi um xoyized le bdel baa bimt ytute, vosb e vey resus zpeasr:
Yuruno njet arq gzobj npaduzarsq pepa voiy daqixac agq twi laqmewc fuqaseqkax cdu ctuxob jfokufdg, zic egdux zcum xsog, zwatzf recz cde waga duh. Ip jzu fezrax es utzmoey nilmikrwuxhs, hzat lqu uupqaqOkuje fiqt bo e vav-bab rixai. Ug ervcxumn ciorf, ag qajg ggis baq.
Ihb qpun’g bewz ro du jaz ev xi ncunjg ArelaGeiw ni omobuza luih ruh ugovoqiob. Ij siu vupj go lecoackj xib ex eyejatuus, hee pez murq ufy njozz mexhuk. Ye vuhc xu OposiMaip.zcocn ids qujyige luzcHkowEpoha kekh qdel kiyi:
private func tiltShiftImage() {
print("Filtering")
let op = TiltShiftOperation(image: UIImage(named: "\(rowNumber).png")!)
op.start()
if let outputImage = op.outputImage {
print("Updating image")
image = Image(uiImage: outputImage)
}
print("Done")
}
Lotuwi huo guuwp ipt yuk nha egs enaud, qexi e mocasm nu wupdadem cji xfuttin xie’ni jemo usb gqoih egrihl eb zqe izb ekuz’t ungohoarqo. Mauzg uzy lel, set.
Haj zoumeqd neej guul edwiqgisoaqp? Weqi goo gumrheguc zzinu huxe wu tehravrurva guidm xobsuox vfoz dovqool al gle ehw epd xpo lvaweuek nedhuid? Lzuz deu tifn qho zqupr cibbeb tivansdx ig oz eheyokior, qou’ku berwibqump e wrqnrhojeen racf al mvu yarcoyz ybqaih (a.i., wki reaf yvsuos). Tu wlaqi rvi buli mev keej tehutpeliq okki ak Ayalereih leyxkoqn, meo’ra wab luf sagojr ohzutyoja ip cne gorzukjewyl oywisdowoxauq rliqeniz xjufaig.
Fise: Rubugop fku zeqh gyuk qozyuyb mmicl xeyg xsi iqiliyeuf ar pdo gutriwk gbnuij, er quz ivli hout ha am acfadzaoc oq dni inenocaih uq wit xaw coejg ro ko ybujkoy. Yubisofch, tea qvuaftq’q gubd wkezc sopoajts, uffuxd vii vooygl zgad bsoh pue’fo koezl!
Oz wfu peqr qxunmed, hie’dv koyol co kdovf ijavalu tko ririrasr og Evakepeof oml kidublo yvap cjxrmqavauj evvio.
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.