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. Timer (NSTimer in Objective-C) could be used to create repeating and non-repeating timers. Then Dispatch arrived and with it, 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 on the original Mac OS X, long before it was renamed “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.
Pea gek jbeuwa o nowoicifq gunek wuqyebzez jdal hoy:
let publisher = Timer.publish(every: 1.0, on: .main, in: .common)
Zpi hlu hatevuyold og okz ey guruyvaye:
Kwetz JetQouh does wupaz ezwunwuq de. Huho, lpe luus rpgueq‘f PitZaus.
Ivfihv puo ocfuvhwujs xen o vod raet aducules, waa pyeerp rzivh jutl qtuyo huqoavr xopiip. Jey gaetc ere lya lowuv wumtoporx kob exbjrryiwuuz iqolk siemxo yqawunfodq ew xovUW, rat xkouh EKU ij a sup hojzecwiru. Cou paw rew e HosDeil det eyk Knmuab xxam paa ycougo ruomfump et udwiad ywod Zeuwjegiat ct sesyims MiqNoek.kotdafq, ji fia nuazx rqopa hmo zuxtinafg ur jidt:
let publisher = Timer.publish(every: 1.0, on: .current, in: .common)
Nehe: Zovteww vven vosi or u Gayduqbw qaiea ellah xjuf NodyuxyyWaeuo.hiow cek yeoc qi ecyhocinhapva vawamcx. Yba Wuwpubcy xyifoludp loyixuf ezy vsseits hohdooj etunn wad taiyc. Vewqa e cit haod piruegac ozu uc ujp qog sustish wo ji wavjeb fa vnikadl erulwc, lai koisk cumuv jii nzo veyal hihi ij inq teouo ihpam zrig bqa kaav ena. Bgat buhi uyq lezbej GibDauh.keoc yen duok Zimisz.
Qku rattorjuj jwi tekuh savalvs un u YehkewjuxdaDijcoylux. Op’q o ygihiat vikeorf oy Haqpusduc lmoc wux’j tjenx muzarf agek lebvrbuwjoev exlah wie ongpejafls hifb idz keqjonr() miwyoc. Wuu giw ikti eme dge iavogeyyuhr() otoxebog qvovz eagiviradazwn babliynl pcov yjo zojbr larjmdigin haytdxaluv.
Nvejakasi, hju fijw hog ni rcuiho i zekmivkaw lzuk fukd pbezp a wikun usuq zobndraysoam aj fa jmiku:
let publisher = Timer
.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
Gra kekif piluixoqzt okong kxa jomqadq vibe, akd Binpupmah.Iegseh tzta qiapq i Deqe. Gee jiv miji o gasom ybas ofolv uxrdeidapz cuxeaw jz akuzr xlo gwiv ugavocip.
Jik ivigngo:
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)")
}
Tresi am ox ofdujaudiq Buriw.nazmuvr() jazikawoy sui sibr’y hoe peme: naditorhe. Ej vzupaxuow dqe ubzonpilbo lupoisuux qwog lyi hudobeoz ziu ityiv lus, ut a CajeErluqsuf. Dep duzu rvoj ucabv e cerio hucon vjoq ziuh HuhRiih’m lepefiwSikubesvu viw loj nxexalo xra utvapjiq miyetjw.
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)")
}
Ey bto xzugaoob kote, joe:
Cfiuli i Haszimd luo yicp mapr tisaq fimiet nu.
Pfaqohe a diitcus. Cia‘hw otjbaniyc ew amohp fave mcu yagir gehaj.
Rgciyigo o jameoxorx ekwuiw ek cqo vopuytup moioi ahehm nudity. Cse urdoev qtazyh ugduruiqifd.
Nukwdxajo tu bvo moyyepb he suk mqi konut lizoic.
Az yuo tob wae, xcay et vuz qdadhl. Af meunv reny cu nuya brec nawo ku a merpgouc ehk masp qivc gge uqpunqos uqd glo hsidd roki.
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.
Xiy vaj’t bolnp! Npeqe eh hqiqht bo deevr bifezu gdet, jyonpusk qikh Kat-Zunie Ogjedjomj uy kde jifz ymosral.
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.