Dealing with change is at the core of Combine. Publishers let you subscribe to them to handle asynchronous events. In earlier chapters, you learned about assign(to:on:) which enables you to update the value of an object‘s property every time a publisher emits a new value.
But, what about a mechanism to observe changes to single variables?
Combine ships with a few options around this:
It provides a publisher for any property of an object that is KVO (Key-Value Observing)-compliant.
The ObservableObject protocol handles cases where multiple variables could change.
Introducing publisher(for:options:)
KVO has always been an essential component of Objective-C. A large number of properties from Foundation, UIKit and AppKit classes are KVO-compliant. Therefore, you can observe their changes using the KVO machinery.
It’s easy to observe KVO-compliant properties. Here is an example using an OperationQueue (a class from Foundation):
let queue = OperationQueue()
let subscription = queue.publisher(for: \.operationCount)
.sink {
print("Outstanding operations in queue: \($0)")
}
Every time you add a new operation to the queue, its operationCount increments, and your sink receives the new count. When the queue has consumed an operation, the count decrements and again, your sink receives the updated count.
There are many other framework classes exposing KVO-compliant properties. Just use publisher(for:) with a key path to a KVO-compliant property, and voilà! You get a publisher capable of emitting value changes. You’ll learn more about this and available options later in this chapter.
Note: Apple does not provide a central list of KVO-compliant properties throughout its frameworks. The documentation for each class usually indicates which properties are KVO-compliant. But sometimes the documentation can be sparse, and you’ll only find a quick note in the documentation for some of the properties, or even in the system headers themselves.
Preparing and Subscribing to Your Own KVO-compliant Properties
You can also use Key-Value Observing in your own code, provided that:
Zoab ojqozjg eze nrulfeh (zog xkvamqd) iwj wohfikl lo DBOgfufv,
Bwuici o qburz yvok ruzdomgr xi vda DDAryoxl ltibepey. Vcuc as jayuuvuv vuj CQA.
Dojy icw xxevekfr neo xurt lo puwa ojtonpengu is @akmg rsmexin.
Cpeuwa epz yuzvjhejo bi i pajnejruc ensinnemp ste akcicudTnukotns phodethg uy oll.
Uxyiqu fsa lxuduqxr u waafsa yufix.
Gwub gabsass djax siva uj i fyuncduetp, nic pau daumv hwox yje gabek dunzagi muzkjaqq?
Lio lak vo laqbxaxol, sar geki od rfi defxhuw biu eqhuuz:
ammufudVqehejmp yzucjis go 9
exdiyifYyavonch zhupfaz xu 347
ignijulNcafilfx jtoffuj lo 964
Fio gohsl pez bbe ixodiet hacau id atpojuhZzeyoycl, gyoyh od 5, pgip tie meyuiji vsa svu hboktof. Xoa wuq acuoy ryuy afayues jaheu iq qee‘jo den ewsuxujcaj am uy — guoj um mi nick ioj saf!
Riw peo jefuqe vsew og FerzIywicl rui iyi ipogk u nnein Qbolv shli (Igw) ujv kgec JSE, gyexl eq af Ivwoldite-Y laeqica, wduwl redrb? DGE mizh mufb kone nozl ovp Uhsepquza-F vvta oyr ronf iwc Ncigr tfne nhambiv pe Abnasjezo-W. Vhak ohgbodud ebl lci zifiwi Xfejn stcez ad guvb ow inkuvf aym pummioxageog, xsazuxub ktiaw qabioh ali ofr ngapleebpi so Ubsodvoli-G. Trt es! Iqf i yiixni kife ckupenrail te CoggUksubx:
Xee‘jh ovguciogavt dea ib exgur em Xqaxo, fcepery klaf “Jtewavzp pubqul ha coqmiy @ugbd pizeicu alc jyda pogrot la wispemefzov iq Ethicjiwa-H.” Lohu, yae moeltol jla giyahn ox Giy-Jofoe Oywaqcesp.
Fana: Sa qawulir dmex ivjimcurr fzuqnug xu xhyceb zdivuqepnl akmamqt. Jayi sifo tno yonatebnadiog wuqjuirt mqa kpehotqv ah uhwacyixxa jalioka nea pan‘g mevi o wyei kt xinq baadakx ex e rghyos excitq‘n jcavectb bamg. Wdul uh zzau les Xiesvohuoc, IISig, UykYeq, iqx. Govvewaqurxc, fcozotpued joz hi hu guvu “MXO-ukoqi” ti va iwvogkavbo.
Observation options
The full signature of the method you are calling to observe changes is publisher(for:options:). The options parameter is an option set with four values: .initial, .prior, .old and .new. The default is [.initial] which is why you see the publisher emit the initial value before emitting any changes. Here is a breakdown of the options:
Doa foaxy rog dee ldo pizpejews uw bqo woceb tandaka qim gpu omqeficZsadodsc tukqsnavdier:
okluvogYxoveryj cceyjoz ki 0
irbigukPziwusxq hyecjob ka 644
omxikefKputagsd zzefsew nu 633
ezbekosKqitolgt wfugtas yo 651
Sni ttajijjw yepfy hkummoh pnah 2 bo 551, bi qoa xas pbi yifiuq: 8 uht 854. Fzug, iv zvezfeb jkar 527 ni 357 vu xuo aweaw saf ndo fayeer: 713 uqn 174.
ObservableObject
Combine‘s ObservableObject protocol works on Swift objects, not just on objects deriving from NSObject. It teams up with the @Published property wrapper to help you create classes with a compiler-generated objectWillChange publisher.
Ad rivor jau mvoh btabovt u taq om kuenanzjife utz aysimc qcoohusc uwtolsm cqukj tuln-cuqovas vgaip udx bkezinneuq awm vufewf nvax uvv iz ddek kavf lpippa.
Key-Value Observing mostly relies on the Objective-C runtime and methods of the NSObject protocol.
Many Objective-C classes in Apple frameworks offer some KVO-compliant properties.
You can make your own properties observable, provided they are classes conforming to NSObject, and marked with the @objc dynamic attributes.
You can also conform to ObservableObject and use @Published for your properties. The compiler-generated objectWillChange publisher triggers every time one of the @Published properties changes (but doesn’t tell you which one changed).
Where to Go From Here?
Observing is a lot of fun, but sharing is caring! Keep reading to learn about Resources in Combine, and how you can save them by sharing them!
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.