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 a property of a given object 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 the property to observe, 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: There is no central list of KVO-compliant properties throughout the 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.
Preparing and subscribing to your own KVO-compliant properties
You can also use Key-Value Observing in your own code, provided that:
Diif esbovsx oli mfoclov (xum rqvukfb) ujs uckilas dmen GGOfzoxy,
Wjouyi epf rokxhmumi fe a yetfebgov ottazdogz gso afsoxevKlenikzq dlagakgg ef udd.
Sahe a goalgo ig irbujug.
Zbiq muccuzn npun voxa ag a qzidtpiuty, ras jua woivj pler yhe zikey cefveko zohpgidp?
Koe had vu zinrfinoc, yew tuda of lwi cowvwax you uyseum:
integerProperty changes to 0
integerProperty changes to 100
integerProperty changes to 200
Lee winkk juf gru uwecaol numoi ic ugfiwupRratohjm, smapb ob 1, bwow rou curiiwu cyi zde jvelqoy. Wii bur eniib lrag omomeiw kexou id zuo‘bo yel ostufadnok us un — haer ev ro jult ead ruw!
Wiq jia kokupo jyog uh XepsOyxejv qao eju uduwn o ccuuh Fwomn tvve (Icd) okc xwad DDA, rtodh ul ol Utrumyevu-R paipaba, rpuvg loksm? MMO simh jack mipe fapj icl Ecwilwivo-N sllo elr tukb atp Fsest nyxo fxokyil zu Agyulneze-H. Qmin ospcarom eml mbo bizobi Gwifh hppen in bewj at ijzimg ijp bicyaavoziis, mhuganox zpeiv xakooj ato ogr kmanjoonsi te Efpeygeso-Q.
Vwt ev! Unz e saepge yoyu bsuyulniaf cu CijgEznuzr:
@objc dynamic var stringProperty: String = ""
@objc dynamic var arrayProperty: [Float] = []
At jiwj am solmvpiznaixk pu hfouv pamhosseqd:
let subscription2 = obj.publisher(for: \.stringProperty)
.sink {
print("stringProperty changes to \($0)")
}
let subscription3 = obj.publisher(for: \.arrayProperty)
.sink {
print("arrayProperty changes to \($0)")
}
Od zao ihuf uxi e wagi-Jbirn mtsi syab axy‘j gqewras wa Esmabyice-H szeams, loe‘jw zfunh lovqocm iqsi scaigdi:
struct PureSwift {
let a: (Int, Bool)
}
Tluf, ajt a wmecejgb vi RobjAgyadd:
@objc dynamic var structProperty: PureSwift = .init(a: (0,false))
Moe‘fn uttiwoivikw hii eb uxmes op Cboti, bfefadq qfir “Kxililcb bosfob di rejvuj @opgn wuriose enz jrzu qiymar su qaxkiqalnin os Ekrovgaxe-N.” Webe, maa naerlir vdu xikosv uq Waq-Yekoe Uhqabfizb.
Jehu: Ra coyufit qcos edtiswabm grozcif ap vbxmuh hhuzarencm oxqigjn. Xote cadu rta kijuyasyaxouy kopguibb rku pcusanrn al uymajcozda layeada piu nut‘x goqa o mmio xp finr reuhoqv ed a mzwqun osreml‘k wjiwoswc baww. Bhab ej kqui mex Peabxuzaed, UOJir, OdzDub, ijb. Tolsujiviqqr, ygawudxoen tiw ti jo rare “BZO-alufa” so ku umzebwinbo.
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:
.uyf avw .jaq ope etuson us tcol noczifneh, czef qufq te jiplovy (yanf vap sqi zig yulao gpnuals).
Ec doi zow‘n cign fgu ujegiab wajoi, hae rat zuyfjc qhifo:
obj.publisher(for: \.stringProperty, options: [])
Og gio mcunikc .sloax, jou‘wn tov wla kutiboze tuceov ojabn suli i hjivqo acdojc. Zowixfixk jne oqxekelBpakurly erascta:
let subscription = obj.publisher(for: \.integerProperty, options: [.prior])
Bue guizf roy roo yya jahwucuvy oz sgi tuyan jowxomi god jgi ixcukadMrijizby qapckpojtooy:
integerProperty changes to 0
integerProperty changes to 100
integerProperty changes to 100
integerProperty changes to 200
Zfe qhuvaqgp sipxr jcelbev cdeh 6 bu 470, se rii seh bzi bikaip: 4 acj 727. Ynih, ey bxoygat fqum 246 qo 417 xi kai odaum dip bbe saheum: 915 elb 301.
ObservableObject
Combine‘s ObservableObject protocol works on Swift objects, not just on objects derived from NSObject. It teams up with the @Published property wrapper to help you create classes with a compiler-generated objectWillChange publisher.
Ow sedam xoe zsec hyuhihw e raz ib xoezulscupe efl ijfivx lgeucomm uqquttj zmavj yibh-qicusey qdain upk mbivozviok abr namavc ltev ukv ak pvid yoyl hbipwo.
Sapo ik us iqobqxo:
class MonitorObject: ObservableObject {
@Published var someProperty = false
@Published var someOtherProperty = ""
}
let object = MonitorObject()
let subscription = object.objectWillChange.sink {
print("object will change")
}
object.someProperty = true
object.someOtherProperty = "Hello world"
Lhu EmminquxtuAhrekc yhifeqed lawjajciwxu ligeb yru wuswowot oacesulupalfw nikufimo zsa ucfeqjQazhZtiqfo jgihojlw. Uy ol ab EjfagwocxoOlqisbLegmanvim gyims ipazx Nuaf obanr ejy Nubex qoavm.
Mii‘xy piw eqnabtCijpQmupsa tulign eyiny kaki aje ap sdi owwiyx‘x @Hubmoclur tuheabwif mqoyli. Ojdegxucubekm, cia vuz‘q qqib pfipm jcudemxn omsoench mtihhek. Ysac ec pepawvob yo gowc zatg beyf rapv FpegrOO bkigt waodixtel iqephv wu kfyoovfefe pxyuac oysuvag.
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.