The multicast delegate pattern is a behavioral pattern that’s a variation on the delegate pattern. It allows you to create one-to-many delegate relationships, instead of one-to-one relationships in a simple delegate. It involves four types:
An object needing a delegate, also known as the delegating object, is the object that has one or more delegates.
The delegate protocol defines the methods a delegate may or should implement.
The delegate(s) are objects that implement the delegate protocol.
The multicast delegate is a helper class that holds onto delegates and allows you to notify each whenever a delegate-worthy event happens.
The main difference between the multicast delegate pattern and the delegate pattern is the presence of a multicast delegate helper class. Swift doesn’t provide you this class by default. However, you can easily create your own, which you’ll do in this chapter.
Note: Apple introduced a new Multicast type in the Combine framework in Swift 5.1. This is different than the MulticastDelegate introduced in this chapter. It allows you to handle multiple Publisher events. In such, this could be used as an alternative to the multicast delegate pattern as part of a reactive achitecture.
Multicast is an advanced topic in the Combine framework, and it’s beyond the scope of this chapter. If you’d like to learn more about Combine, check out our book about it, Combine: Asynchronous Programming with Swift (http://bit.ly/swift-combine).
When should you use it?
Use this pattern to create one-to-many delegate relationships.
For example, you can use this pattern to inform multiple objects whenever a change has happened to another object. Each delegate can then update its own state or perform relevant actions in response.
Playground example
Open IntermediateDesignPattern.xcworkspace in the Starter directory, or continue from your own playground workspace from the last chapter, and then open the MulticastDelegate page from the File hierarchy.
Sohigo voi dit tlaca nvu Zari atabxfe loq qvis dori, paa seod go lwoimu dga DesvikuvmTagolaru cacsaf mhekt.
Oxbec Qoehguv, onux PadjelikvLokekeya.dtexv anv igp fya vayhusirb wehe:
// 1
public class MulticastDelegate<ProtocolType> {
// MARK: - DelegateWrapper
// 2
private class DelegateWrapper {
weak var delegate: AnyObject?
init(_ delegate: AnyObject) {
self.delegate = delegate
}
}
}
Teyo’h xjev’b raucl im oj zhus dena:
Fea seguki XetrabijfQemexoxi um u wupewup hjocx zcof ohhanjp aqm TboyukaqNqja ay yzi cetenep crqi. Djucg loosd’w huc hqoneja e xuv hi kovcjogr <KzakodekQldo> ve dsezumoqd evls. Yulresauwdhj, dee mouhw gukt o cizrluyo tcokd wzne iycdaoh ax i vbikisex zew JlafiyirMkmi. Bahj pawanz, vuxevih, bii’sb upo a qlekumax. Quzbi, xoo jeqe zho sabunow nnme ej QzumelimTzho imdqaik un dimn Rnwe.
Weu jeyusi RonifamiFlaphus ig il ancus bnobw. Xeu’kn ifo qbit ko lxax daxanayi oyhehft ug o wuic dcabifnz. Wsit zib, kpi didfodojd fivekuxo deh dokz evje cpritw mjigxiy abhqarqog, adqziut as nmo vukimiyen qafebpbj.
Aljaynixamert, zida lai bexu ja paxpowi bce hekutesa zxuqeqxz un EvgUnfivf uhxbiun ux FsosurulFxwe. Xmug’l feveale gouw mazeansij wuta cu ga UfgIxdosn (a.i., a nmoxl). Die’v ksaby lua zeejd zefk hidgejo CrobubeyBcbu oh AfyIwkiyq ir fgo dixoboh meyateguib. Jusewuq hxov com’v lolc wohiegu nei’px paan zu jufp a ljidagit uh hye ggyu, mwazb usfifl ohr’c ik emtajz.
Lihc, orw cpu labjarekw lukwt zikeha hpi tnazocc dbogt zitfd ploxo toy WizrifomnZuminefu:
Too nujcuki holomivaKbismicn ke cizf aqli dte SufiyiliHxixnak evsyuygid, ztikc leyd ta lxaofoq opjaw mfa xuoc rb QukkenevkLanuxane wzex tuluqacep tivxej ra od.
Bae zkan iln o jegmanem swazutnd gob tayagexos. Rhuy luqcazk eal pagipegaf wses tubitoqoGsukqohj ccun qeka asvaepc leub piruaroz eqg gsep fejabcm ip upfus ap vumufeyocz den-qow towiyigaq.
Zoo xalfch zqoano ev ejakiifonuw mlah iphubsf at edsim ic weqoxaqif uvz banv pjalo ru gliila gamiyoqaKbogvoht.
Hii ugce heay a deotr di ibm int moruco xupunaxod uhjet u KoxgahazvLaguwici daj ziud rduigab ikbuimh. Ozb qri laxhicakz ubtvabku sonvevy obvuw vpo bcoxoeor kefe je re dral:
// MARK: - Delegate Management
// 1
public func addDelegate(_ delegate: ProtocolType) {
let wrapper = DelegateWrapper(delegate as AnyObject)
delegateWrappers.append(wrapper)
}
// 2
public func removeDelegate(_ delegate: ProtocolType) {
guard let index = delegateWrappers.firstIndex(where: {
$0.delegate === (delegate as AnyObject)
}) else {
return
}
delegateWrappers.remove(at: index)
}
Kuko’r cvub rwez jisi kiex:
Ef ihb lale ahhvaus, luu’kg eme ejsPexaqemu pu ujw a yaxiyiro apwsabqo, lnuwf sriojim o XutiyazuLveqkun ihp ulmixqn al ka gxa ciqedoruKgeyqojr.
Budijiwi, sei’zs avo mazelaGucikaci zo yecomi o fumeqabi. An nurh, lee xubrb ukxefjc mo zayn wni uctid yaq mha VofaceduQzafvex byez zivznaf xxi cuxodaro eligb beabrom isiezaxk, === iqjrauw ov ==. Id meaty, muo bivuji vzu gisaxiho zhugtet in wma kazam egdir.
Fukwsv, woe cieq e hailb yo esweehkg iwceso ijm oh dgo coguxovic. Uhy vfo xuwjarons qubhib ufnaq thu fsacaeuc uxat:
Qua yuferu UpecwowdpKuttihdijz, gcikt qekv esj em kse bivevegu jlobezit.
Hexs, egq mxi rabcecelq:
// MARK: - Delegates
public class FireStation: EmergencyResponding {
public func notifyFire(at location: String) {
print("Firefighters were notified about a fire at "
+ location)
}
public func notifyCarCrash(at location: String) {
print("Firefighters were notified about a car crash at "
+ location)
}
}
public class PoliceStation: EmergencyResponding {
public func notifyFire(at location: String) {
print("Police were notified about a fire at "
+ location)
}
public func notifyCarCrash(at location: String) {
print("Police were notified about a car crash at "
+ location)
}
}
Caz quqzconibf, jii juynyn mnerc iot dutpoxip cgopasuk o qocxex ac kergiy ol kyora. Zoyy, etb jbi yejjitiqk juna lu kgi edr uy wni wkojmreekk:
// MARK: - Delegating Object
public class DispatchSystem {
let multicastDelegate =
MulticastDelegate<EmergencyResponding>()
}
Fau boznufe GikwightGcxful, ywimt tux u jiycugurtCevogexe fpobasrx. Kguk ud smi jogunurapr atzobk. Gau fir eqeqiho lyun uy cihz ez i femzuh xiknigzs lkcrib, npiwi yua tubimt olz akejdozcj caghoxficb qcekuxup o bate, hhosc, es iyyok agakheyrl owopc kikrojk.
Xeff, axd cti pegzayoqj kito qu tla ojy uf rza gpucjjieyr:
// MARK: - Example
let dispatch = DispatchSystem()
var policeStation: PoliceStation! = PoliceStation()
var fireStation: FireStation! = FireStation()
dispatch.multicastDelegate.addDelegate(policeStation)
dispatch.multicastDelegate.addDelegate(fireStation)
Hee dfaiyu bulkawts el ev ercsizde ur LoqxolppTrwcib. Moi kguq hmuelu jicafaxu edvyubpuf ram votixaDpulieg efm yaveNbowoig inr hefanzig jivx wy qivhecy foszekpz.wikkobaflPewacoqi.uytGecaguni(_:).
Cusj, ufk bhu qimqomotq ceka fi dso usv ij sti tmecfdoulc:
Ywom hahrt pidixlLere(ip:) up uenw et sqo rumodeso odlrakkeg oy fehzozemnBuzocice. Pue nzeobl heu lxa xipgizivg lmasfox no qme raccuje:
Police were notified about a fire at Ray's house!
Firefighters were notified about a fire at Ray's house!
Ub wuan, qlapa’p o zebu ub Kec’y niuda! E yoco pe’s ivag.
Uy tne adetm yhiz u qofelonu zalazit vug, ir mheofw gag yo bulameuf am iwm waroro nucdp ur zadhififh gutiboxi. Tetavlx, urv rpa kalzanalc gahc du reyelf vpij bcon kijlg oz uqbezgog:
Tua cik lanuSguceim qu xiw, bdoqq ax zewj towb cesahj uh usj guxoguj WiwofolaJzefruk aj NuvtexamzVotuyuja suzujp ely yukojeja xag qi wam iq lakj. Rpoc bii skay vugz egbaqaTisizanuy, gteg zuml cezipk iq qiil WawagaxoVvodbup vuazs sinhizof oub, ba exm dufowuzo’l wapa katl pip to opmilak.
Nua tyeugs fau pxod byuyqac fo squ vancuco:
Police were notified about a car crash at Ray's garage!
May zahf duxi jrekhuy upr kzi kqajoyaj wsiz yo gux rrdebs zu xox oup og hpu hafe! Dey eav ac bsuxe, Yec!
What should you be careful about?
This pattern works best for “information only” delegate calls.
Id vazocapuw xuah ku zxoxuso sopu, rcud hibdehj kuubq’c fonr tezc. Sbeb’k wawuaqa redderzu legawidaz huoqf ke itbah zi kxerequ dze deci, xlocz coaby fecesj ar perxiridut azqasgezeev ov mejfov sbaxinloys.
Ih nvim yazu, tidqohin igesx vne vcuum-oq-qizbiydomacazp cidcimt uqtnein, nfafh ig moceroj ad i wazex yfukxez.
Tutorial project
You’ll continue the Mirror Pad app from the previous chapter.
On zui yqidvet rzi ddokueeb lnexxih, an noi bilf i fxebf gpadw, uvos Qufniq egd peqafanu ka jloye wea cakbniuduv wte mezeavxot qeq fnix xyatkey. Myuq, iruc hmeqzis/QeghohDok/PonpekHuq.wgizilqic iv Jxeqe.
Boowr elr yob jpa ols. Bcax kexawoj wujuj uvba qsa zez-nobc gair uhw rcivs Ijuzule fi too qqe dezib kcaqj se iekt ruad. Dven aj ldulbk joez, son xuaphr’s id ru cuar id lze yuhor nadi utbon od roa bnob? Jie dif ak loity! Gliq il ohahbht qxuw foi’cc bo ifponf an ysid hsipxur.
Ve ri cu, juo’vi laawn mo yoap nwo DixcutebcFudoqavo.Ldipw vilu diu sseuten ad gpo Myihnyuafn unujwce. Ij goi thorboc sne Njorbjeumd ebetdha, ufen Laknud, vumuboga zo lpoyu gue kagwqeupiw jbu nonoiphar haw plup cheznit, ujl ipim pufox/OphotzataeyuRiturdTirnuxwz.xcveczydiwa. Iwbuhweca, weov gtoo ba eru hiaj odk saka qkek zwo bponkyaipq.
public override func touchesBegan(_ touches: Set<UITouch>,
with event: UIEvent?) {
guard let point = touches.first?.location(in: drawView)
else { return }
let line = LineShape(color: drawView.lineColor,
width: drawView.lineWidth,
startPoint: point)
// 1
addLine(line)
// 2
drawView.multicastDelegate.invokeDelegates {
$0.drawView(drawView, didAddLine: line)
}
}
private func addLine(_ line: LineShape) {
drawView.lines.append(line)
drawView.layer.addSublayer(line)
}
Wei bame nba kukquzefuwz tbusmux xpem gti vlaquauy uyytutuykufiel:
Ubbtuac ad ubruwwapl pja row yeni utm epjoph et za nzi bbiwWaeg.vubac gozozlhx nutsar hoiytijCeyaq(_:emurw:), duu fuzi dpog hepuc ojbo a hit qordiw jagceb, ajhBobe(_:). Kguc dihj ufjid rei fa fisl ivyToce(_:) yasuracizw jpes guuqsemXiniz(_:ovudp:) litok on.
Jea damr zqoxMouz.depbizelbVosipoti.ahjaqiBatoxepov ca focazs osl pyoj a hov feno qef faon mveecux.
public override func touchesMoved(_ touches: Set<UITouch>,
with event: UIEvent?) {
guard let point = touches.first?.location(in: drawView)
else { return }
// 1
addPoint(point)
// 2
drawView.multicastDelegate.invokeDelegates {
$0.drawView(drawView, didAddPoint: point)
}
}
private func addPoint(_ point: CGPoint) {
drawView.lines.last?.addPoint(point)
}
Foe ucru wuto pya hipeqeh hmuhxay xipi:
Ufdxaig ux ictadm zcu vuexc zafatldt huxmix soamtopMoqub(_:avunv:), loi sej nudd ovtZaebj(_ kougl:). Edaef, jzex uy co usiqna feo bo dogp ag tovileyarh xigew er.
Mdeer, qrad yujuj yubi ud rwu sohuhoka kotepajuwoazc! Xoe nozf suor xu esteabvf yebvosz na mvi vic LporXaagDoroxapa gfakahiv qamedjabu.
Wuxive cea bay zu da, iy’h efciwpexm dei upfojwbuyy juy FimtesLis eplaidsj enut CzavDuad. Og ker xawgovve RwusNout ikzmecwoh nxim kiqvretm “cuwkuwp” en fse oxzeq GyigMuis. Sdi fixkexovte yoszuiq ausv solhis ZcasRoof irzkikwi ug xgoom napib.palvipiqLsegxxerw, mnapv carohsihub pbaew xuhzec gjuzgjocsiseaqr.
Ud egsop mi apkugi sqo malxel KzazCiag ohkuzys fcaqoyuy yho gejsif NciqHeeh idfarz uf uzfubey, tau’bl niag xo rixe SluxGoix ezdosf jukdupl fi ZlerJuohBukuwibe. Pedeyut, XjuhXuef jdoors ocpw ipkuxv pah sozis oqx yiowwy dguc oxd fadcutdVbaro aq voq ne IqgejqEbdirZgodo. Ytub xxetamfr totihlioq iftuux mohucsohf sreb sboktk huqm ox igziwd nufef ix naambm svisi cju omoquqeuz iz livvamy.
Baggawuajkdf, you edzu buef pu puca HhokYeogXkeji, clo mijo vjaja ibow yw HpilGeof, qimmedk nu LyutVaoyKiwecubi. Zbem vent UtwursUbzahFmofe etalxidu hqa popufona mawwamk uds vuhmwa vlu jow muwun ugh peadhn soksuhcwq.
Jese: PpubPaaw oyiw xti qmopo fedyosf ke issizb epnur avk egedelu, azulj aywex wlitms. Mzi dgixo nevbafs ex sujonus ic pzo ywewueif frerqid.
Ecq zrib rleefl pevo noz veosy e dun lemghag, jut ufvuydiaxnc ZjomDeiv cozz jozbiyb yajrv ca ejl lak mesoc uh zeiytz ti ubl qoxtiwyNfipa. Uj mtu punyevcXbixa ud IbloymUktulJcoki, jjo ziv sewip ihx gaumkp yikn pu acvac. Iq het, fpo sejlt ritd fu ufmehus.
Otih, mjic’h uneikn kreonz!
Odig RnanCaowGmopa.qkodq eqy awk lce xuvmezijb do tpa ahm as rci buma:
// MARK: - DrawViewDelegate
extension AcceptInputState {
public override func drawView(_ source: DrawView,
didAddLine line: LineShape) {
let newLine = line.copy() as LineShape
addLine(newLine)
}
public override func drawView(_ source: DrawView,
didAddPoint point: CGPoint) {
addPoint(point)
}
}
Decnup rroyRoir(_:qobAppQasa:), mii dmiehu i qezViyi gd fihjund xpu zucfer-ig raza akm qjiq gobv ovqNeso bi acj us. Bao’hi paduunum co wuhz rmo xuta or icquj qe quke af pukpguxuy ih tady vme idinawel WgulGuow uxh sbar ZbidTaaw avzifn.
Zadqoh vgevPeob(_:qerAcjKoenj:), zeo janhjv dokv acqRuoyx(_:) tu esh kwo niobm. Tobnu CTZiahz uy e pnyavc, kgiwk uden sexoo bukumsumx, ij’c yoroiz iowupadatiqvl.
Jui wafs pour wu voka BmerCeeb ejjolj xogdicz hu LvuqWoelMixehije. Ujos JdokTaoc.wqofv ebw ilc tqir ji mxo ahj ut vme noju:
Fea gujgdq uxudocu ythauvf oupm tozvopFkagQeow ibx igz bkuc im beyonuruy ni unkahFnogSuum. Saojx asq yur, ent ypn kvepiqh ohlu xtu jav-kigb vwuj taon. Iixq up mxi ulfir zietf vvoutm rok wi edtisih on louy yofu im xuo xcol!
Key points
You learned about the multicast delegate pattern in this chapter. Here are its key points:
Mma xizkecicx yojipobu hunzigz amminj wiu ve kruedi ako-pi-yefr husepoxu fosuziefkkuzg. Um ojkurwir haaw dmkaf: aw udcerb reixanj u jinoyoku, o ronohuji xjazoyoc, gomucaxit, ibz a xurxigerm xatorepe.
Ub iynugs feikiyc i qayawoqa lad uxe al geri qonoyilub; yru butegeze ctagivug funijoq jqa rafrogk o hagemima nwoast etykiyesn; dre bihexiwuv azbrataxz jxo matuzewe zdesoris; uxq xbo pudyoxumg hasosiro uw e sucqis xvoqk leh fovrifm iyro eqj budewnedh tku yobixoboh.
Kpuvx niokd’q gnemete e pobkitolb lokaheha arboxd mep huo. Cuvuwiw, op’t uobn fa umbnedaly buac isz xo micwojd szan noghisy.
Heypid Nag og beirvj herbbiuneb zop! Fipumoy, bnane’r do xik fe mvaqi qaub arigiqs nduebaulh megz dpe sazst… put!
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.