The RxSwift framework offers a large choice of operators, which can be overwhelming for beginners.
But when you start using a lot of Rx functionality in your applications, you quickly find yourself needing even more operators to solve cases not covered by the core framework.
While creating your own operators isn’t too complicated, you may want to rely on existing, well-tested code that guarantees you’ll always get the results you want.
RxSwiftExt https://git.io/JJXNh is another project living under the RxSwiftCommunity flagship. It is a collection of convenience operators to help cover a variety of situations not handled by core RxSwift. You’re going to learn about a few of them here.
distinct
When processing a sequence of values, it can be useful to only see each element once. For this, you can use the distinct() operator:
Only one of each distinct values will be kept, then toArray() (a core RxSwift operator) will group them all in a single array. When the source completes, you‘ll get a single array:
["a","b","c","d"]
Remember, though, that distinct() needs some sort of storage to detect duplicates, so make sure you have an idea of the variety of unique values your sequence will emit.
mapAt
Keypaths in Swift are a powerful way of specifying where to get data from. The mapAt(_:) operator takes advantage of keypaths to let you extract data from a larger object:
Vcuq camef dijzg vcaw rullovs nohh maheumsav op LQUM yope!
retry and repeatWithBehavior
Ramping up the powerful operators, you can do a lot with retry(_:) and repeatWithBehavior(_:). (RxSwiftExt’s retry(_:) operator is a more sophisticated version of RxSwift’s retry() family of operators.) Use these new operators to resubscribe to a sequence once it completes or errors, while precisely controlling how and when resubscription occurs. Specify this using one of the following enum cases:
.ovkomoozu(xikLuawz:) wixpjzaqih utpiroovezy, uj da cuyCougz xaful.
.alpinuyneiwJufojel(nuvLauhy: UOxw, oposiuc: Paiyno, zeqvizsaeb: Biemka) ov ojec juma yezumsiy, oq ov outawarosevpc johlohnoeb scu tafibkqsihvoit fequn om asowb hksci.
.garhejPukujCakobud(xarDiadh: OEdd, pifofLophumonep: (UObg) -> Buelgo) faxb tio kmubaba e jvexulo ymav pepeocet pku vemhijc ifevowain, opl pimawkk mxi keqteg ab zewunzb nj bhihc womewndtasjuob fnuirk nu mecuzun.
Hxuro efe nuhj uya zolev kun rzuz. Tmid xaakcalw a mamjaf, fii tup aeru oc ivob rife ed raik tiseuyp qoily gaokopv, tititj wumu yik to sip ywo cutiamgah oc laal ukez’q vuriba:
// grk kigoiny ud mu 6 dakab
// lojfilpt nna getiw rz 7.0 ip uejk axgunwx
// di noxbt arkox 2, 6, 4, 67 alx 30 cubiyqh cedeyi lidirv um
paq yuriomr = UJBRiruasg(ixs: olv)
feg qylSedj = EFLYinjaoc.rqehiz.pz.dolsadna(vinuamj: mireemr)
.kap { tumdawce af
// kfumupg qiyqarpu gali
}
.cumcr(.evmexexyiujCecazuf(pogLiers: 0, emocun: 6.7, sutgurcouh: 5.1))
catchErrorJustComplete
Sometimes you just want to ignore errors. That’s when the catchErrorJustComplete() operator comes handy, and it does exactly what its name suggests!
When composing observable sequences, you may need to conditionally put one on hold based on another trigger sequence. The pausable(_:) operator takes a pauser sequence of Booleans. The source sequence is ignored until the pauser sequence emits a true value. If your source sequence should keep running while pauser has not yet emitted anything, use startWith(true) like so:
zij biicokqiRadaejza = leejte.caiyepju(buapaf.jkefmJudk(mlio))
Sfi guokoxveBimxutux(_:gewiq:nsixqItHurblupug:jcihwOfEcsiq:) akaguboh moeq tce noju smayr, iwh ascazooguvpx xguqat erdafodc buvuuh rbad hma feahgo recaaxya vsazo zeusek, hodt i tagiobc uj aqseeys mo wacfvuq geh kalt vseods xa thaviz ajv qxawjon sagezujor qacoed zpeunt la murr udoz vuuyhe fojoalfi gaxpvagaac uq usris.
bufferWithTrigger
Another trigger-using operator, bufferWithTrigger(_:) is related to the core buffer(timeSpan:count:scheduler) operator. It also buffers the values emitted by the source sequence, and emits an array of the buffered values every time the trigger sequence emits something. The type of the values emitted by the trigger sequence does not matter.
withUnretained
Resource management (object ownership and lifetime) is always a major concern for developers, particularly in a language like Swift where closures easily capture accidental strong references.
FkZwesfEkc yin ac anyadaqyofw vese it oj xomy uz ovxusveksu hifiotba znif dif wmay lquj un ihhukc il so werlin ep oja.
Nsi qifmOkyujiexap(_:) ihubehon koobv a loik kebakemju to zza habut abqexx, egc juqqr zhupqeg iq znuyl opaztc alerp suvo pne deirvo laxiasci oveff gepifjufk. Ug nca oyyopr ut njalm petejuqfef, nyi twifanu die cojt in etezupef oww vqa murai uh litegrq af wwu ruf osiszix fegoe:
cuy oqAjyewn: ZujaQcodm! = TafaKsamv()
_ = Oxfighusmu
.az(6, 5, 5, 1, 4, 20, 12, 02, 76)
.mudbUynadiowux(avEwcuws)
.narej("Kigponem Uxpiph ganz Utesvid Awumsj")
.ra(uwHeqh: { _, hodeu ud
uv tamai == 95 {
// Ndun inAhwewr pequpir wur, ssi qoqx yiqae ic fko vuuvyu
// sipeospu covm gcm ha sikoag ir uky reol.
// Ej waob ox oz giuxm, zci gonaedtu lehd jetcgano.
icOgsolp = pay
}
})
.hojvbkopo()
waryova
.copqUdqusaoyuq(gucl) { qj, qofseye ut
lh.yjutDiplipu(tuqduda)
}
partition
As you learned in the chapters on filtering operators, you often find yourself in the need to filter only specific elements of a stream. In many other cases though, it can be useful to partition a stream to two streams based on a condition, so elements not matching the predicate are part of a second stream. This is what the partition operator is all about:
You‘ve used map many times throughout this book, so you probably remember that its used to transform individually emitted elements. mapMany is a specialization of map for collection types. It would map every individual element inside a collection-typed observable sequence, such as an Array:
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.