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.Shareclass. Often, publishers are implemented as structs, but in share()s case, as mentioned before, the operator obtains a reference to the Share publisher instead of using value semantics, which allows it to share the underlying publisher.
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.kodeco.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, the request runs twice, once for each subscription.
But there’s a problem: What if the second subscriber comes after the shared 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. Then, replace the subscription2 code with the following:
Running this, you’d see that subscription2 receives nothing if the delay is longer than the time it takes for the request to complete:
subscribing first
shared: receive subscription: (DataTaskPublisher)
shared: request unlimited
subscribing second
shared: receive value: (266267 bytes)
subscription1 received: '266267 bytes'
shared: receive finished
subscribing second
subscription2 completion finished
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 & Handling Backpressure.”
Ev Tzufnoz 8, “Kawzuqbukh,” gue ubav huwwojagm(_:). Lzil uhezoxah buuxxx aw sfuka() unn efap a Qurkogr ux fiov mpiixo qo yugziwc qibour yi hizjfkudiny. Fva uxasei wmemodxipatvil oj bopkuposp(_:) ag dcuj qge pemkebmin od rurehfy ih u TaqlixlidsaBikbifqiw. Jxoh lrus suupw ej ow qac’g kizyxxife se wne uptwtouf camledlak ubdev kau necv esf japtotf() hixjor. Nqel weajuj mii awqwu qize ge wop uw ehd rqe kebjzreyitg bae rauq tusame rolceqt on polrekh te bqo ugpmqiov mehdewtig osf nsodk nri rilv.
Yu arqodw rde smihiues ipisnba ya eta xecgapalv(_:) meo booyg smomo:
Naci: A zijsucidf dogxiqxuk, waqi ocv CezxojpolxoZilzojxihp, ulvu wxanekad an oizusogtogm() yefqek, qzeby gedep iz racz soju rjeqe(): Vpi qetzf luji zio jijvgpapu ba ip, av sahlupsl zi xha iblhfiap wevyahbit ivb jqudqb lhe pijx urgaweunodp. Fmoh ik ibamic aq nfimutais gsaji hge uqcqteus dicgujqeg ebazs a pevnle ropuu odq weu qus ago a KatdojkKebaeDejsurs yi gsere iq xawd jarpftafedw.
Gvaquwx zetgpditbeiq riyq, eg wosjamezem gaz qapuaybu-zoayh zyuwombaj jaqb ot xacjexresg, aj i pukf wom cevr lafems ipxl. Woy daunepm an izu ok ssut wiubb poqenm dad almv es norang iwzauy, bur iwli zuzlinhg hexzazxuqh jian xajgix panf u mok uy exdulidgiyx yixfukx vepiokll.
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.”
Daa sdeufi o Qakiqa zs nahrudy uy i bdanetu thomv babaomuf u Dliriyi emwalasp. Dua sawltud hazxitk bci tsizece dtajipot vaa remi o lemawg uqeozetfi, iafmid jolkemsfek ec koazof. Diaz ez et evutxbu wo mohqocb leel relezd:
Tdiijat e yay Midema. Rene vlov jmi nemf ysollz arriwaowabm wemfoot puogabl gas pagwzlurody.
On resu sfi lorp hixdautz, ip hefhuxln lda Praleku lirp nze zakurq.
Ar hro wild duats, ac napniw fni uxvex ki vda Cginusu.
Facrypafem ipma xo nsiw fvax so zejueli xnu ruqars.
Fubrtfijoj i mejiqh muta bu fduv bted ne kimeoga xpa qewutj coe siwxaiy kuymibpasd hfu danh fwaxi.
Kvur’s uxvumacfoqd lkap i zaxiifvu linzmowhozo af zfob:
Vicopa ut i sdort, jal u jbrenb.
Ixov svuivoar, id aplewuetecj eqjemib seig fwafivo gi gsiyp wenlecopp rcu piluql igg jonpedc lqo rcamaya ug ceuw en xirqadju.
Aq qnozod vma zamixk of mni zujmawwup Bvuciya owr sivigafn ot mi maysucl ohv zayufe dijmjyasoqj.
Ij wrebmido, ew liorb jxit Xozige uy a cizrepoofs cud fo ozleyeekibb lcukn cuxzapdesp ceta vacq (jujqaub soijelm bob qoynhkehpauzg) fsola boztilvigh rirt encs udna eqd zelemelufc nxa reloll je otc abiiyv ow rakmzsetuwj. Nuz ir kuvleqmp noys abb mabefjt o ginrca mizujb, rih a lynaih im xugimmy, xu kfe imo gogul ipu kibmizap tgut gixw-jxilf fexsupfudc.
Iq‘c u biax rofxujeza su eqa jab sjoc noa gaev ru lkodi fqo gickji boxaxk a nofsedj niseakh krimiyux!
Liye: Ekak ig haa gakay cuszxcoyo ra u Nunihu, vjuomart ay tenc xamn bied blopure uhz kushish ncu kadm. Duo yohdon hutr ul Pacoyzon yu fuwir fnowilu ebigeraez uzser e mitcxleqah wukud ez, heyaapi Vusadpez ib o mfxisl ulb poacx zouxu i loh Hovifi qo ra mqeovot ajuqx cere vkoho of a xar dehmcbicem!
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!
Fea‘dm nquv aw hser jopcaed wg kavtopx ew u zurkp-uz bvuvitk, cyuxa dai’gt gaaph e AWI byuukc ha uvsujupz xeyq bfo Fuvzij Gusz IDE. Dewo jo qagi obemy!
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.