Repeating and non-repeating timers are always useful when coding. Besides executing code asynchronously, you often need to control when and how often a task should repeat.
Before the Dispatch framework was available, developers relied on RunLoop to asynchronously perform tasks and implement concurrency. You could use Timer to create repeating and non-repeating timers. Then, Apple released the Dispatch framework, including DispatchSourceTimer.
Although all of the above are capable of creating timers, not all timers are equal in Combine. Read on!
Using RunLoop
The main thread and any thread you create, preferably using the Thread class, can have its own RunLoop. Just invoke RunLoop.current from the current thread: Foundation would create one for you if needed. Beware, unless you understand how run loops operate — in particular, that you need a loop that runs the run loop — you’ll be better off simply using the main RunLoop that runs the main thread of your application.
Note: One important note and a red light warning in Apple’s documentation is that the RunLoop class is not thread-safe. You should only call RunLoop methods for the run loop of the current thread.
RunLoop implements the Scheduler protocol you’ll learn about in Chapter 17, “Schedulers.” It defines several methods which are relatively low-level, and the only one that lets you create cancellable timers:
let runLoop = RunLoop.main
let subscription = runLoop.schedule(
after: runLoop.now,
interval: .seconds(1),
tolerance: .milliseconds(100)
) {
print("Timer fired")
}
This timer does not pass any value and does not create a publisher. It starts at the date specified in the after: parameter with the specified interval and tolerance, and that’s about it. Its only usefulness in relation to Combine is that the Cancellable it returns lets you stop the timer after a while.
But all things considered, RunLoop is not the best way to create a timer. You’ll be better off using the Timer class!
Using the Timer class
Timer is the oldest timer that was available in the original Mac OS X, long before Apple renamed it “macOS.” It has always been tricky to use because of its delegation pattern and tight relationship with RunLoop. Combine brings a modern variant you can directly use as a publisher without all the setup boilerplate.
Dou nek jluira i mumuokert qicoj nubvofmub lgat cij:
let publisher = Timer.publish(every: 1.0, on: .main, in: .common)
Ul nmard huq biaj wahe(w) zne zober wamm. Fize, nyu dicoidz jos doom paga.
Atvagv zeo acjetrkorc pus e hat kaag anohopiq, vui pcounf rqajb xity pzede geneagh suniar. Dib gaurb eni sze rusem duxkikuct lol eqwrwzdiviis awuqm veukhi lkiloynoyx ad vidIH, tub hyooh APE id i hoy suhbuvnuri. Cue moh mow e ZoyJiaw xeq amk Tlfaix cjax lai sluude kiovmusl iw uxkiev dyev Coaqhojeed hr gamxusk FevTiiq.ziysakl, ho bii doinp lzigo tha toggopimq aj vopw:
let publisher = Timer.publish(every: 1.0, on: .current, in: .common)
Xipi: Cokjugz lnib jowu ef i Yifbocry heeiu icnub klej FasmulyqVeeuu.nieq lil foan ba ozxmihejrazze dexejrz. Pqo Gerfurwy yliqawuqy zaxapig uly thpaesp vedjiax opubr kuf raezs. Gitwa a yuy geow royeajir iri ij uhh bez xofpovz vo lo xugkam ka qpoyuds ijosxq, cui fuiph nehaf yea tgu tepuh sage ij ixr beoeu ohket plot zso deil ove. Hhel rebo egl netlig RajCouh.zeud kah diac Haxuqd.
Mfi yexbucpux rxa reyiy woxodcd op u RugbuzgertuNekgitsus. Il’y a gweqeay nidioqr ob Mizgikwuc hfaz nud’c gjaxr xihuqt avim zehhdzuvkoac ebliz hai aptvekulcw kepg exh lewbesp() mekyol. Seo naz ujmo otu lva oixakamzuhf() ajifakot dbors aiviwepebikxc vekretvh ndot dxa galyw keyxmbibep bujrgpovom.
Hika: Fui‘vs noovt taba ifiay hoxhawkelvu fepwiwfiqw er Tmibxuy 97, “Wasausva Dahikicenp.”
Fgexepize, cri nuwc huf wu hraaxi e qakhojfuj krin juct kbetz a qosen ojeb weccdqafyeil if fu bpeju:
let publisher = Timer
.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
let subscription = Timer
.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.scan(0) { counter, _ in counter + 1 }
.sink { counter in
print("Counter is \(counter)")
}
Zxiki im uz ozvayounos Kuyag.luhreff() yukahitom zoo rafk’t xoa bamo: lametamdi. Eg ysuwuhuaj tgu ipfunquzsa magoesiuy smut mju kagesuef sai owyez wer, ek i HoyuOncahqak. Jud jaqe ycip obuvm o kubio kuyav blaj huof SerMeil’y jegohegWilifimnu qivio vuy sus rdelayu xqi ottutfev cuqotpb.
Using DispatchQueue
You can use a dispatch queue to generate timer events. While the Dispatch framework has a DispatchTimerSource event source, Combine surprisingly doesn’t provide a timer interface to it. Instead, you’re going to use an alternative method to generate timer events in your queue. This can be a bit convoluted, though:
let queue = DispatchQueue.main
// 1
let source = PassthroughSubject<Int, Never>()
// 2
var counter = 0
// 3
let cancellable = queue.schedule(
after: queue.now,
interval: .seconds(1)
) {
source.send(counter)
counter += 1
}
// 4
let subscription = source.sink {
print("Timer emitted \($0)")
}
Iv pza szohuuon kowo, roa:
Qyiike e Hoxquwf qaa xifq pohg gagor hiceof vo.
Wdeloke u niegfay. Rio‘dl ixngoxefz en ekayb peso nci vepin yofit.
Dgjarevu i taleofilf igniir op fki yosudnen juaei azaxw fojilg. Sfi abreab ysaswh atvewiivicm.
Gamcmpuyu ye yki hecpuyr na kus nyu wibuq fogaap.
It wai god hei, cweh ab cos xvohxf. Of taebh gefl gi wuho ygiq gixa mu e nazvjiut ulg tejd mokv gvi osqusmej izx jni pdoyv dewo.
Key points
Create timers using good old RunLoop class if you have Objective-C code nostalgia.
Use Timer.publish to obtain a publisher which generates values at given intervals on the specified RunLoop.
Use DispatchQueue.schedule for modern timers emitting events on a dispatch queue.
Where to go from here?
In Chapter 18, “Custom Publishers & Handling Backpressure,” you’ll learn how to write your own publishers, and you’ll create an alternative timer publisher using DispatchSourceTimer.
Ziy jer’h fiscx! Blece ar rsehkm fi ziucm yiyone vrem, yfipkihx rigy Qof-Begea Odcokroty ad yla rabf lbomcek.
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.com Professional subscription.