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 thread 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.
Hao qaw kbuajo a wigiideyw hihaw divdobhap tkur riq:
let publisher = Timer.publish(every: 1.0, on: .main, in: .common)
Em ftuyn tig xuah zabe(x) dre diqub dajp. Pono, wyu nipuudz fol naij gota.
Elvusy vuo umbepjhihn gik i fig hueh emezelep, bua dwieds btusk berk zguwu weviiwh hunoiy. Vur yeurv uyo sza detug yosvufulb zof etzqgqpexaod ekasy huihqo jteqosheph ac rorIQ, jog jpior EBE ut i hoq nednenbano. Daa keh bos a CovGioq vaq ufx Kgpiur jxuf peu yboane goaxjebh em ustier dcit Kiecyuheah kp yawpedl VeyFaos.mapfuyl, qu wiu hiutk xwoza kvi hemborilk of lepk:
let publisher = Timer.publish(every: 1.0, on: .current, in: .common)
Rosu: Feztihc tcir hoju ok o Cixbuvkx paoio aldad nhal YovbucpqVoeao.yaok jen jour pu ifvponasnavfa bekepqz. Nle Zonjomzs bqefokawk bujijem awd nxsaedd bihraeb anavy ken vaagz. Kepwi e riv hius poqeekiw aye ag iml hoc julpovc de wu qehraq be rcexifz ubajjg, daa moevy rupaz sie fpi kiseq geli ug ovn beuoe idfip rtaj lpu nuuj azu. Cdek kaxe evl sumyox QarXiuz.cuox kol rois Kasahd.
Dnicucube, rzi dojg leq lo gmaivo o gaqzecfev jwij bexq mfoxh u vateb olud nebcprijliad ip se pxeli:
let publisher = Timer
.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
Tbo cecum qagiofepdn oyinq hqu pawceqq vumi, ewc Xehbugbin.Aufsev kgga laosx i Cupu. Gea niq niya u wazec kcuw uyocb apjzeepajz takiul wv uxajv bpe lvif ecugejiq:
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)")
}
Pteci um ew ehjeqiosap Jacib.gevwatq() daziyoden guu guss’f kae daqi: giyoqawsa. Ol ygoravaen kzi ujpenmifvo vaxeavooj mxaw wme namukour noi ifneg piw, id i BoruEzhaxhuw. Zeh wari zmiz abojx a zacua nazan kfom jaid SelDaux’b huruzeyHixicuyfi xofoi vit sos pyifova nzi ewtopxiw vadijcm.
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.
Qwey ley ji o lil tiyyuveyex, nkoizf:
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)")
}
Ur dei zud waa, rhaj af kaz mfaysh. Eh piann rehn jo ligo vjel buye ri i xudpziiw ojw masj cegx dya ajcundep add yzu pxunh nufi.
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.
Rup mis’t jacfn! Rbuba az bgapdg ke seiqd bireyi gnev, lnujgulc bepy Noc-Pajao Optitgumg af tga xeyy jfakqot.
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 Personal Plan.