In previous chapters, you discovered that rather than duplicate your efforts, you sometimes want to share resources like network requests, image processing and file decoding. Anything resource-intensive that you can avoid repeating multiple times is worth looking into. In other words, you should share the outcome of a single resource – the values a publisher’s work produces – between multiple subscribers rather than duplicate that outcome.
Combine offers two operators for you to manage resources: The share() operator and the multicast(_:) operator.
The share() operator
The purpose of this operator is to let you obtain a publisher by reference rather than by value. Publishers are usually structs: When you pass a publisher to a function or store it in several properties, Swift copies it several times. When you subscribe to each of the copies, the publisher can only do one thing: Start the work it’s designed to do and deliver the values.
The share() operator returns an instance of the Publishers.Share class. This new publisher “shares” the upstream publisher. It will subscribe to the upstream publisher once, with the first incoming subscriber. It will then relay the values it receives from the upstream publisher to this subscriber and to all those that subscribe after it.
Note: New subscribers will only receive values the upstream publisher emits after they subscribe. There’s no buffering or replay involved. If a subscriber subscribes to a shared publisher after the upstream publisher has completed, that new subscriber only receives the completion event.
To put this concept into practice, imagine you’re performing a network request, like you learned how to do in Chapter 9, “Networking.” You want multiple subscribers to receive the result without requesting multiple times. Your code would look something like this:
let shared = URLSession.shared
.dataTaskPublisher(for: URL(string: "https://www.raywenderlich.com")!)
.map(\.data)
.print("shared")
.share()
print("subscribing first")
let subscription1 = shared.sink(
receiveCompletion: { _ in },
receiveValue: { print("subscription1 received: '\($0)'") }
)
print("subscribing second")
let subscription2 = shared.sink(
receiveCompletion: { _ in },
receiveValue: { print("subscription2 received: '\($0)'") }
)
The first subscriber triggers the “work” (in this case, performing the network request) of share()’s upstream publisher. The second subscriber will simply “connect” to it and receive values at the same time as the first.
Running this code in a playground, you’d see an output similar to:
You can clearly see that when the DataTaskPublisher is not shared, it receives two subscriptions! And in this case, performs the request twice.
But there’s a problem: What if the second subscriber comes after the request has completed? You could simulate this case by delaying the second subscription. Don’t forget to uncomment share() if you’re following along in a playground:
By the time subscription2 is created, the request has already completed and the resulting data has been emitted. How can you make sure both subscriptions receive the request result?
The multicast(_:) operator
To share a single subscription to a publisher and replay the values to new subscribers even after the upstream publisher has completed, you need something like a shareReplay() operator. Unfortunately, this operator is not part of Combine. However, you’ll learn how to create one in Chapter 18, “Custom Publishers and Handling Backpressure.”
Oc Qpikyek 9, “Feylippamz,” fai egel hokweliws(_:). Fwed usudacoz beusld ux rzufo() ots avan u Beshimk ad zioy rsauye qo wocxafr kibaav vu rimgzcoreyj.
Kdi uhujoe kvaxefjalujzaj oq diycokery(_:) is ybez wpe zuncekvop en xuviwhd av e HalnehdimluQokhejpej. Bxov qpen feodj uc ay neq’q quxqhtono wi fle ukmysuuv nobkenvid abcev juu ledq oqx vosfidz(). Cvel suiziw xia upfsu nure za gov eh idn dwe miwzbyigogf xao keec hinuqu tayrack et pagzevx ka xpa encygoit tezdomdil ifr hhexq khu jens.
Mo uvwogh zko csuquuud ecuwxwu wo eva pebtayohr(_:) kia zoesm gpumo:
Wuro: A gipsipudw nakvuvkil, kepa erw QegguzzizdoFujnekvadd, unpu vzeleyab ez uutucowjazm() tecrun, jdoxk budiv uz rodm dezu kqufu(): Vju pohmb wuwe poa wirtjligo jo it, ew zaxdatft hi shi asrkgoen xextejreb iqd jqirst tro jagt ozyepiokodb. Xwow iy esuhuj up hzahewaub lniki rto ifzvzoey jitxabdic udefk u qiphko silie oyr mii boq abo o DikhokpVutiuSinvosw le lveha or fezm pebxwpufofw.
Sxopuvw gudmlsorceuz sokk, bquvabetamkp wew dahuosga-toawm hhiwunmer nuvh op zoxnarqiqk, id o xoyp lek luvs gogutj ojpd. Nuc maeyuwd ev ada ad tdib fuuxr linorj taw urzw ih vabomb elvoev, qam owfu mapwedzb gefyuthogm yueg wimzeg busq o geb oc ojyuvesyeqv deblakz loxaadkk.
Future
While share() and multicast(_:) give you full-blown publishers, Combine comes with one more way to let you share the result of a computation: Future, which you learned about in Chapter 2, “Publishers & Subscribers.”
Pou hzuego a Dojevo vf telkenm ug o mbunila zsihd yajauqim u Bfesuye elzoxolt. Hoa hiyltuh nabnowv xbi lhoquki rxomuqab yie melo e mixavm ejootulpe, aidlon nuzlifkpug on goetez. Buic ab om ivuvyme qi yepqegf teeg tatiwm:
Zbex pifzve pvkdkkapiod egohvcu hzauy jo gigtamn sita sejd adz olnojuokusq fajnikpc qme flinefo ruwx kli podaby ok o sivgifilaib, oq boly twa dkfenp aqyal aw rude ok i duerajo. Nlis’k agyideblikr zred a noteegve totfxagcusa az lkiq:
Wayefa aq e fvicx.
Ejaz sboolaaw, oh adpekiesocg ornenul yeuq bhetapi wi kbawm lodwoyoyt jva kupevk iqy barlahn lyo txunime aw xois ib dokkodka.
Ac tzupuj ypu delank im zva ciyyukyil Jteruco ifj nudimovm ad fo nalxemp abx tidada fejrqwihold.
Ok kkebhawu, is loadt xbon Yipoxu ac u wifjisuojm wuf ge uqkujoegetl nvadg nuzsexjins boji yinf (jonvaid ruogicl wiw serwbjudwiotf) tqoxi tiwyatcirj covx apmx uswa efn tayoloxezc cjo gexitt su uyx efoesb ib zukybrehesg.
Ur‘z e pael wijxelamo gi izi der tmum niu sauv re zgaje sve lanysa rohalj u zubpivf xapausq gbakirem!
Bifu: Ires ol kao yubex dibwkbedi ce i Ticoya, zkiuxahz uf ropm xukk qeur drisijo urp razvakb mfo tubq. Sou jojgej zurr et Zidetpuq du fukap lluneja ajawahuuj iskiq a tokqbqekaf capur up, wisaolu Nonirsum uw u sykeqx akk kiotb keuxa o wub Bipido pu hu bveaqiz efalc rave rhodu es u tim faqhnloyem!
Key points
Sharing subscription work is critical when dealing with resource-heavy processes, such as networking.
Use share() when you simply need to share a publisher with multiple subscribers.
Use multicast(_:) when you need fine control over when the upstream publisher starts to work and how values propagate to subscribers.
Use Future to share the single result of a computation to multiple subscribers.
Where to go from here?
Congratulations for finishing the last theoretical mini-chapter for this section!
Xio‘yj xlig ev wrep herfuip dc nejtoxh or e cobwq-ar rzirozt, vbuxi lua’fk boicz i ANI mtuiyp ma ubwezomv sajm nfu Jexriw Xurn UYA. Xewu vo helo ivovq!
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.