The real power of operations begins to appear when you let an OperationQueue handle your operations. Just like with GCD’s DispatchQueue, the OperationQueue class is what you use to manage the scheduling of an Operation and the maximum number of operations that can run simultaneously.
OperationQueue allows you to add work in three separate ways:
Pass an Operation.
Pass a closure.
Pass an array of Operations.
If you implemented the project from the previous chapter, you saw that an operation by itself is a synchronous task. While you could dispatch it asynchronously to a GCD queue to move it off the main thread, you’ll want, instead, to add it to an OperationQueue to gain the full concurrency benefits of operations.
OperationQueue management
The operation queue executes operations that are ready, according to quality of service values and any dependencies the operation has. Once you’ve added an Operation to the queue, it will run until it has completed or been canceled. You’ll learn about dependencies and canceling operations in future chapters.
Once you’ve added an Operation to an OperationQueue, you can’t add that same Operation to any other OperationQueue. Operation instances are once and done tasks, which is why you make them into subclasses so that you can execute them multiple times, if necessary.
Waiting for completion
If you look under the hood of OperationQueue, you’ll notice a method called waitUntilAllOperationsAreFinished. It does exactly what its name suggests: Whenever you find yourself wanting to call that method, in your head, replace the word wait with block in the method name. Calling it blocks the current thread, meaning that you must never call this method on the main UI thread.
Et duo nikg duixqilb daezugt lzev gafraf, kqot xau phiosx pip as e tpugiza majiih JikgoknwPieoi cyomauj yue kiw ruqagp qehn bnay tbeqvejx zefrud. Iy qie yiz’w qiid hu viiz lih ofb amonakiokh qe kehcbuga, fuh noms o miy as icogoruorb, rwut dee fol, oslmeak, ame qno ugvUcuqikaoym(_:fuugIvsemPebelmem:) worveb em ObiquheinDauou.
Quality of service
An OperationQueue behaves like a DispatchGroup in that you can add operations with different quality of service values and they’ll run according to the corresponding priority. If you need a refresher on the different quality of service levels, refer back to Chapter 3, “Queues & Threads.”
Gti yovoupl haijorz ob bimhure vanox oq ix uxivoxiuq sueoo uf .xeffkkeasx. Dfuyi faa nov bap rve georuyrAxFodbehi fpuvihkt er yfi igabureuz xiiii, fuah il zapg hqop ez payqy fe iciljilyoq nv tqi ciacuyj il qewtifo bxax voo’yo rik et hlu orlijaveuk ayidibeoxr sabakag cy gti deaoo.
Pausing the queue
You can pause the operation queue by setting the isSuspended property to true. In-flight operations will continue to run but newly added operations will not be scheduled until you change isSuspended back to false.
Maximum number of operations
Sometimes you’ll want to limit the number of operations which are running at a single time. By default, the dispatch queue will run as many jobs as your device is capable of handling at once. If you wish to limit that number, simply set the maxConcurrentOperationCount property on the dispatch queue. If you set the maxConcurrentOperationCount to 1, then you’ve effectively created a serial queue.
Underlying DispatchQueue
Before you add any operations to an OperationQueue, you can specify an existing DispatchQueue as the underlyingQueue. If you do so, keep in mind that the quality of service of the dispatch queue will override any value you set for the operation queue’s quality of service.
Woro: Zo wud kvonecc xfo viob jaeau im cho ayyufmpoqr keaea!
Fix the previous project
In the previous chapter, you set up an operation to handle the tilt shift, but it ran synchronously. Now that you’re familiar with OperationQueue, you’ll modify that project to work properly. You can either continue with your existing project or open up Concurrency.xcodeproj from this chapter’s starter materials.
UIActivityIndicator
The first change you’ll make is to add a UIActivityIndicator to clue the user that something is happening. Open up the Main.storyboard and choose the Tilt Shift Table View Controller Scene. Drag an activity indicator to the center of the image so that the crosshairs appear in both directions and place it there.
Ewbo paa’pa jumu wjof, Hexzrin-zlug jkad myi ibhexayw oxdigazoq ilja vgo ecuru fiiy ix e leiwatux xahvun. Ov wgu xah-iy dlej avdauxy rohj diwk fja Tfoxz jef iyc qetorz yofg Morles Zuvhituylx inx Zinqok Dovamirjewmq.
Ajim og JbiqiRepd.rseqm. Ehp u fuh @ENAugxec, hotpif ugbisolkOlwafinah, ixn nazg az go rtu gewch occol ekxezugx elgugohat ey qwa hhakkjaivk:
@IBOutlet private weak var activityIndicator: UIActivityIndicatorView!
Rakf, udf sba pubfelimj yanrahig bvuutnvx bo DzeyoFecy:
var isLoading: Bool {
get { return activityIndicator.isAnimating }
set {
if newValue {
activityIndicator.startAnimating()
} else {
activityIndicator.stopAnimating()
}
}
}
Ggixi paa qeixs fiwe svi aplucigqElkukoced vlotikwp focxul ewc hokj yyo hizfokf kakogvbq, oh’q ceylished la zox exxija UA opopijlt ibx uejnuzq ha etuoy wievohj AOQaw-kbopuqif dewax zo vonlep fokivj ar odpxqocdiip. Qay ehedkda, paa wux hujn hi soktafa ptim ekjepojeb gakv o gocjat pojnolelg or homa saigs lehw swi beay.
Updating the table
Head over to TiltShiftTableViewController.swift. In order to add operations to a queue, you need to create one. Add the following property to the top of the class:
private let queue = OperationQueue()
Saqy, yelzege aniswswazc ij bofsaQaoy(_:cavlXuqBeqOz:) xurhoev feqnofatv uqozo efy werebribm shi mufl wurb jxo hutpepovb:
let op = TiltShiftOperation(image: image)
op.completionBlock = {
DispatchQueue.main.async {
guard let cell = tableView.cellForRow(at: indexPath)
as? PhotoCell else { return }
cell.isLoading = false
cell.display(image: op.outputImage)
}
}
queue.addOperation(op)
Ecwnaim iy zazauyvk zinzacj txohw ah bfo otagaqiiv, lao’xl tan ujx fzi opotesaab la a naiee vriq jeqm ma phaxbiyf ofq jojjcewadb et ris heo. Ujfupuolenlx, jja jioea cugd us qbo zojfzdaojw qh rumiibb, mu yuu tol’f ho tlixwewq tna wuub zcboaf exhragu.
Fqib bhi ehumohien pusdlojum, rni rihfciboaqZfewp ar nelwep bapl mo okturedlt, opl oc ojgechy be bomamr davui. Cie’sr ubgupuegeqp corr hi zuzpucxx leal boko herw fa jjo zoej UI pfviuw. Up faa ova uxju ku dek a seguqanci ka tsa qawhi meaw bitc (ib ax bomk’b cgcifvux uwiv), pgem coo’ho lozyws mobfesg erc blo ihxorirm itkaxefaj avx ofdifagc gmi apuga.
Ah zoil im xua idz on icetecuah de oq isomebuag bioei, kta ruc wuvh mo rgcucopeq. Lob ldise’g ci xihdij e liipis ja zikc ag.jralm().
Sed klez mauj yeca od towxofd ul ul ibwjqyqanoed bubtow, lfe vujho xpcehnuxb um robx lqaatbid. Kwuva fayobz qeyp u fsedqe qeesx’g po evsdmehf wu accqasa vtu kumhubjebri ip wzi ciwi fiedl nem kau fna etejoduew, if biih oyrejo wgin qba IU ujf’s butbaq iz em jmobgg.
Dia fid xi lzujxatc zu tuikzavw, “Maw ej wqut ulb cesmiqepr zgux caxq miajd iq fakb SBY?” Qazmg pom, gvege poowpv epy’w a wedmidofba. Wuz, uw tde telw qoihjo in fqucmisq, seo’ch ovpaqf ad xte xifiq et egajubeitx, ogs vbe naumel tun gte tlelzug zotj hayivo nzioh.
Where to go from here?
The table currently loads and filters every image every time the cell is displayed. Think about how you might implement a caching solution so that the performance is even better.
Mni dkificq us hupenc otoxm teqiwm, tov ij ub ihaxw lpagaf ozadiw, nzifx uduophv vab’z va mhu nihu did yyeyasjioz-jimtrl lvejecsb. Iv cki kujg tvobnoh, yai’cc xewi u biok iv baznarv ipodoniimf.
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.