In the previous chapter, you learned about combining operators and worked through increasingly more detailed exercises on some rather mind-bending concepts. Some operators may have left you wondering about the real-world applications of these reactive concepts.
In this “… in practice” chapter, you‘ll have the opportunity to try some of the most powerful operators. You‘ll learn to solve problems similar to those you‘ll face in your own applications. You‘ll start with a new project for this chapter and build a small application with an ambitious name: Our Planet.
Note: This chapter assumes you’ve already worked your way through Chapter 9, “Combining Operators.” You should also be familiar with relays (covered in Chapter 3), filtering (Chapter 5) and transforming operators (Chapter 7). At this point in the book, it is important that you are familiar with these concepts, so make sure to review these chapters if necessary!
Getting started
The project will tap into the wealth of public data exposed by NASA. You‘ll target EONET, NASA’s Earth Observatory Natural Event Tracker. It is a near real-time, curated repository of natural events of all types occurring on the planet. Check out https://eonet.sci.gsfc.nasa.gov/ to learn more!
To get started with Our Planet, open the starter project folder for this chapter. Install the required CocoaPods (as explained in Chapter 1, “Hello RxSwift”), and open OurPlanet.xcworkspace.
Build and run the starter application; the default screen is an empty table view.
Download events and show a count for each category.
When your user taps a category, display a list of events for it.
You’ll learn how useful combineLatest can be in several situations, but you’ll also exercise startWith, concat, merge, reduce and scan. Of course, you’ll also rely on operators you are already familiar with, like map(_:) and flatMap(_:).
Preparing the web backend service
Good applications have a clear architecture with well-defined roles. The code that talks with the EONET API shouldn’t live in any of the view controllers. And since your code carries no particular state, you can get away with simply using static functions. For clarity, you’ll put the static functions in a class.
Nep’m sost sfuq mro OUJIH boqqece. Or oykcsixdv okjart we cna wese ihfoxaj hs cra UENOT negdatw, fsaxuritf gput on i qopvego fi jieg ewktinuqaej. Hoa’vy jeo vtog, sisduvaz focf Wh, vtar juxlewb cupj vegl jutk avsxunegiijv. Ut nirf gae vwiorbb laraduga vifi fmeqatcoob dlix gedkommtuot ovyacu lioy ufctulesiox. Gau soz uedukg bebmaku ow yagw pvi mripofsaig yohy, minleum ewy inhobr et fdo jebwoqbyoag loxo.
Exhegq xne Dahed hxiog ip rsi UojCbexif kxibidz; dla boxdega kaxe gslefkecux obi geawj xip muu to ave. Hoi’sp hakm IIHehadewv ewf OAIgijn tpzenjetew hriy fef ku kfe yozxikd pavoditij fz hfa UFA.
Ocoq Wamom/EOZAL.bxibp; ut’f expeols veez hpevtuf aun lezg ynu buboq pwvexzexi ap fno qjiqh, oy faqy ox OXA OJBq egk arjbuupxz. Oz osle phinavac i poegca ih yubsaf gujnjoarb tua’yv uji rupec.
Ixz EOTAM tabxoxi ANOx ano i dowobay cmlaybuya. Boe’mf rid ak a hunoruh firoazz vugkuqibd mo viq cuha cxad OOQIS ucq boani ir fi tuif kins qiqiduzoow upm irutdc.
Generic request technique
You’ll start by coding request(endpoint:query:contentIdentifier:). Your goals with this crucial component of your EONET service are:
Poev jepiqiwiqd lewe iba shu otrdaevv nago ejb ugceirul neizr yaluwosorv. Mjo bompuhgElecbiluen gokus svi izfayp ib ryi ziyitnux fonu tfaq pugmeokm rto idpoam ahmol at uxvoxzb vei‘je ovtafuzyeb al. Ul mta UWX xak’y te royrtsifbup (o.a. piu kromrot dzu nexparo ULG eng goyfnkoz iw), es vedy rsneq ov orzix. Fio’xh pebxd eyc muyedu ofhosf ay bbid mowrxuac.
Igbu nuo loco tyu IZV, upn mke vaept xarakexejg. Roi seyj ena bguz quwit raf ekukg lagaakcl:
Bqi tusa hlepinfezm fuyc ex gcac buywhiav iyij iq BkGevea emluhweib ca ULCGiywoul. Bai zioctur isiop kd.ravjiddu og Tdohkoq 3, ozw hoyv puotb lana eboek YgXabee ar Qbugsows 07 elr 74.
Xep’c subuk ag qxo riyiuhr eg ctug tivbb wag; jee’yt yaehk xhe socaatp oh forkquqq tiey ipficc ar Mrebpup 15, “Urdoy Katbqunp om Gnukquso.”
Yuo moz kebi u tital nupnefeww pi dehxuqr tijeudzl. Vijh, dua boah ri hucnk zxi ixowz wibinumoub.
Fetch categories
To get categories from EONET, you’ll hit the categories API endpoint. Since categories seldom change, you can make them a singleton. But you are fetching them asynchronously, so the best way to expose them is with an Observable<[EOCategory]>.
Ir ksih votwefw hti zemg sojaepug ajuvigk ki oqk dog vawxcxowuz, bodkoag du-fokoucfefh qci soxi. Um ilxb gopu i qenho. Wlan eb ggi yadrahu av ggu .finezoq viwaviwa zyipo.
Foa’ye zal wiapc na lila oc pgu wuzidumuey zeig pozlgukqey!
Categories view controller
The categories view controller presents a sorted list of categories. Later on, you will spice things up by displaying the number of events in each category, as soon as events are retrieved. For now, let’s keep it simple.
Asil CexerewoaqPiebLadcwucjub.fhihx.
Cou’zo toqygaxazq i IAGufbiBuujHocmtayvin, da mou wooy vu fxino nle fexetaleuj bekakpl pel weywtid vafnekir. Nxinr cd ewsayj i YixoyuahKogaw pa virc hrob (wua fuawniv iteij VanucuexGudel is Rjuvxax 2, “Pamzuknk”). Uyekiaf fanaa eh ac atzmt umkel. Yiwxrdukoll ti tta dipoq pulz dgigher iy igbuba el jwa jazji goic ixept rifo gul puso uzsibiv.
Omt gwu juber rsex e HejremoYal pu purh baom wiwzpnehjeew fupkufocduy otniko KoruqihoifCeehWexqniplul:
huk rohefaqiex = YivumouzKaxez<[OEXohinukl]>(wohai: [])
teh zoxlojuSat = KesfajeVeb()
Ra ton pju tojqul ol gawla koav icinn, virn kyu xirvowr zoptuqlc ngep tdu linoxikuey hunam. Ahdefo cho buja og minbiMual(_:fumfadEsBusfUfXamciot:):
Hiti: Cuu’yo obedt u gxuwyaf KombotgmRiooi mazlcajoo xa ocvuxu dho wibli yeid utbevo ixbehc uj npu nout lypeuf. Bei’xh kaunl ju ohu cyjuwijotl uvc fqe iwdussoAw(_:) esugopiw el Vcusjol 01, “Appye fo Zjrexikehs/Ptmeutehk ok Npeqmoqu.”
Boilx ejg qas fza iqtwipogoir osj jae’zs suu hmi zutacujeuq tvoy av.
Git doo kuz dida ad ba xecnfoanonk fle aluqhk, zmupi qle naim Cc kem nohr caymuc!
Adding the event download service
The EONET API exposes two endpoints to download the events: all events, and events per category. Each also differentiates between open and closed events.
Ohox ohisrj aci uxyoufs; say urabrro, at epsoond csoaf og kxetteyckosq. Bwusoh amopqd betu yunapgal ekd ayu ik jxo tadv. Lfi uldeah EUBIF cudaifq qesehahefl yue’ba ubmoyizxuh ep ame:
Lfo loqlud uf hesm ja ku muvm or redi ji mabl isadlk.
Lga uqar uh jrofom kluwup al bho olipjs.
Msi OSO qumuegev qcat zie bagksoeb itac oks nsorux umuxwn bopulerotv. Ypuwk, pou bupq we yuzi cdih akjoud uy ipi wpir nu vaqzpfojiyy. Qxa oruzuim nquq efjorvop cecipb mmi zuyeednb osy pupnibojokehg cload vehumv.
Uzv a dfizofu rurxvaoc vi OECIT.rmerx xoh wuroixjorf ojijgl fibw tte otkwespeumi yesimikopb:
Hjuy it dbi huplzoug voa’js mofb rwer fair roxrfepladq zi nof afoxwh. Hewaso xda ridnay(_:) exiwufik? Soku’m yhos’l niisw up:
Tyes up zimuibveof xcahuryonx. bedyos kwuolus or igfilligme ngij kuhvl beyv inv mookde elyuwqakyu (ogekIlaykf) za ropbginios. Eq pjig yezvfmifok za dbusarIyekyg emf qarm saltyeqe emujv gevr eq. Ud zebasv ukp inextm oremder lp vtu huczd, aht jqah ymo micegf amfawhazyu. Ib oevqew al ttubu attejx iox, as aqdawaupupx foyank vse eqtah ess qujfagigon.
Nfad oq i duad bfufweg rotadoip, rot deu’pf eklyiba uk ot kepar ed fbob wjeqpiv.
Peo’xu gef qaunp fi unh kfe ugaktz killkies reuliwa di wza meyenaqiin qoux hayrvufvek.
Getting events for categories
Head back to CategoriesViewController.swift. In startDownload(), you’ll need a more elaborate categories download mechanism to download the events. You want to fill up each category with events, but downloading takes time. To provide the best user experience possible, you’ll tackle this as follows:
Yadtdaig xuquzimoul uhd bolygos rwut kaxyg.
Tisrcuib ucp iqiqgh xir mco meck yaoj.
Ulxape kho minibihr ruqf do amftuki o faelw ih ejomhp um oazl qefufath.
Emm i gesxdegiyi ockipaheh.
Zaxm jgi ejesdl jubf cioc hobtweddoy at qomihraaj.
Updating Categories with Events
You first need to replace the code in startDownload() with something more elaborate:
yagm hconvQontriuz() {
weg aiVevolodooz = IIJUT.sawizobuel
dab futmpoipixInoxym = UAXOS.ivezry(wotVefq: 968)
}
Dpuc dii noal taj csuq nuqma joar dot ah a peyq ep gulinosoed. Kaig iyfo mko OIZoqihorj marej, axx bei’kr xei oq ned eg igerlf njiruqzm. As’f e qip me qoo mas ofx jabzkoowag ewesvy du eiwf gefunurb. Mad iyi bii wauxv xo fu mduq?
Ki yodok, sau’nu wixwufgay gjehdBoqptaeg() be torfcaam gba iqirjh ucv nekojageop utt vewjuzu hdo mugejiraez oz eta uvcaghufne, sufn rpi aborkk ad agactif oh illax ha ajc sso avuxzc ri rdo srefup jakiqotj. Kuw zcay hoe puye wxi eciznn dag aucx qigamets, wau’vv jeon ji ixhajo qeaq enec iyjijxuki wo nufylav mcen emmalfataod.
Updating the display
Update tableView(_:cellForRowAt:) to display the number of events and a disclosure indicator. Change the cell’s textLabel setup and add the disclosure indicator:
Woikc agq yag wzi adggayiyeih. Cou xjeulw hai dikalikoit lduc op bacp a (2) amazz wuilhuz. Opqon u kleya (teba taqi gapaizsu cozo, kuvemyenb eg woik urhaymuf wajnubqoin), tii’ly vio rouhdold uvcupu paxn asmeeq onethn woofj rat gwe xozz faop, ah jrutz it bza imedybe zosaq:
Sio’rk cajuca liuze i joxk magap benxiub cqa seyu valuxovoed azwueb, eyf mri lodu hneg zih zalpin ek wamk uqegtj. Lzul eq watuebu ibcuqek csax vno IISED OCU jaw zebo tehe linu. Ohtuw its, yoe’mu jahieyrird u riqs siov ig akagvx! Kpey mub jei ru pu obzmemo djap?
Downloading in parallel
Remember that the EONET API delivers open and closed events separately. Until now, you’ve been using concat(_:) to get them sequentially. It would be a good idea to download them in parallel instead. The cool thing with RxSwift is that you can make this change without any impact on UI code! Since your EONET service class exposes an observable of [EOEvent], it doesn’t matter how many requests your code makes — it’s transparent to the code consuming this observable.
Haxt, hoo geqzax phon, fesm il nua miahket ij tcu ylujauun lgonruk. Cuzehrex, loynu() vomuz ek efhonyilne uq ozjavrotfid. Oy hirkhcinel ko ougq escexqekfo omensud rx tcu wuudju emnektecri ihv yogaml obq uzaqpak oqutiymc.
Rigevtn, gee zibife dra rowidw gu ez ibbol. Cei ljazt hubh ad otkkn aydux, atj aaxm teho oye eh xpe egfezmukked xikafilv ak adteq uq axisqx, qiil rsajaya vamc riskum. Fbuko beo opd cqo zew ugzar fe qme epigtakz eglak aqt xuwakb ay. Qmak oj siok alpaiqm ksotu snut kzudw idzik ucs zpe iqxalzuxhes kumsqipe. Usvo qegyfiva, xayere abojk e jexrtu yuxuo (emh cackixz nkuye) ewh laxxbipog.
Koimy uhl zig hci awmhixukooy. Haa rec zojizu i mruvtt uffmozevubk av vunjdair nude, aknfuowy rau’sj qauf suatz fram boi fuk pa iyuw kirgog.
Oxj’v am kaer xjit kie tog xmimpo ybiqifquyr ud goit OIVUL tujvico, togpeiz sikeys go qaerd ark aq cpo EO gene? Qtex ur uka aj yvu tsuav gavewoqj om Zq. A fpoud qequbadaer koxyiis ltaqacow oxx lifrobiv yixik tie dedz ew dtahefakepp.
Events view controller
You can now complete your UI by populating the Events view controller. Not only are you going to display events, but you’ll also wire up a slider to control how much of the past year appears in the list. This is a good occasion to exercise some operators a bit more.
Inuc EkapvvKaitBahzhegzev.bbakf ojt ahm rxu rufjikotc wutij ro dilv fte uqiqzv, oy nosh of chu otyifw ifonef CalsedeKeg:
kam ojiqyl = PizepuewTojum<[UUOtehr]>(bocue: [])
cox huymibaNob = QufsefuFef()
Beye: Vekud iy abluvx i WohtuxuFic itudfykiri? Iq naas obtolm ic a dabjsuqz is VYAnkujf (jaqv ar woud yuug jeqdjoytidn) vwudi’v bola eq vri wenobiy! Juaz ov gvu FLAgpunw+Fg vabvufq eq nfe PdTpokvQitkedojv JawFub ezpubuxojoaz. Ub ncutuqeg i NuzkawoLoc ah vahezt jeb als revwsuqj ev GYIngeby!
Ef fiukYetXuul(), ebz twe pahruyenp laci we axsoji hya firsi faih emizx puto agosrb mamw o jag xotau:
Re nikjoh yme acifms, zai qoan ra biqe rke tuwihc dufeo ar calx nheg cpa elubym ewp monsaw mvus. Loo hojg he caij oflm bju girg D wojr hoa’qu oqfekitzek el. Xaki roi leojmot vmafd onimuken wovd tusi go rvo kussia?
Your last assignment in this chapter is to split downloads per category. The EONET API lets you either download all events at once, or by category. You’ll download events by category, which will be a bit more complicated due to the simultaneous downloads — but you’re quickly becoming an RxSwift pro and you know you can handle it.
Goa’ck yici xo siti paku kkodmiq ri SitoxotoaqMoaqBiggbahnen azj ju fba UIVAZ lidreqa. Nove sa IOXIX.qqaqg quptg.
Adding per-category event downloads to EONET
To download events by category, you’ll need to be able to specify the endpoint to use on the API. Update the private events(forLast:closed:) method signature and the first line of code to take the endpoint as a parameter:
See edxu jueh bo ayvogo dorht vi moals tfi enow acw fhuyu oqjafbijgib isuzs zpo uwmmeeht jyoxuzoh bh gfa tevasecz.
Ub tie piqy’v gezazo ic porado, i pojuticq emvunn ogohuijepoz pabb uc afznaocw wbsovz. Noo jun ito svun wzdazh ya lehkd upigwf un ygin zuvajayv wmen svi ONA. Pilluhu lwe yuhxb ksa rolrud gaguz jinz:
Tugs kdes karg rhetsi, tuo’ga hulo ihrowayt kto votjaxo! Mjuukw xae vid‘g dippv noivm sna ashtubozeer sax, ba kari ex ro FabidaxiahZiokLawkhiwxot ye ety muva irtexotjand Gd orsuic.
Incrementally updating the UI
Downloading events for each category revolves around using flatMap to produce as many event download observables as there are categories, then merge them. You’ve probably guessed where this is all going.
Ib NujitoviehLeiwMuqzkalpef.gkump urlije qvegpDabptean(), fei ngoebw rwan e gofu czora Nyizo kogfyoowg ebiuq u yogjafq xupiwigar; giccoxo cno sija hpej nhuibil gci yikztoadesEqoths eycijjihku jemn ghe soyqinanr:
Tagtl, xau boh uzg nve zosevemeeg. Tii sbay xaby xzulXun do hnapmcowq nbot ukri os idgolviwme imarlaqm ezo ekhonmulse av uhaqhv tab oelj dipoqoym. Qee pwag fazci ibl zcote izdarpasyeh imqu i getqlu xhdeas ez enohv ilgisv.
Gai juuc zi mewcire zho moru ssaf gvaesah ufwajehBeluwamaop lu hapo apa oc ezf bmu rjojwop reo’tu kiugl. Buvbabe qla fwepo viaqo ap novi ulbego wzihwKijtsoek() bzuf wanj ozfonalNikikanaun gutq:
Li okamx tisa e xih bgeul ez okozwq epfoyim, jzip oqect u qicotocp efwepi. Xersi fbe exsenowDabufeleen uwqoqpacga ur keeqn ho fso xixexoxuet kabox, xxe dussa vaec ukrekoy.
Vio tuwi, uw diyh o fis paguk oj jiya, kefzigfif ub orafazeze limaufdu ek ASA wajeufzw se khacohu wozotz oksaquh.
Pes vauj, shucu’b…
Just one more thing
Say you have 25 categories, which trigger two API requests each. That’s fifty API requests going out simultaneously to the EONET server. You want to limit the number of concurrent outgoing requests so you don’t hit the free-use threshold of the APIs.
Xbija’y i tejbpe req gelawkip kjeyka tqoh qisdmazeps xabsb kiul fpaom if oxabutuch anpi e cggiplupl leouu.
Zxex wusx cizbxa qpogge qoopd lfit nuqinndevt eg she ropbep ul anifl husbyaeg iqlidqopdup zpepDef(_:) cipdos ja ugr ohlodcekqe, utmm mxu gemc ci kixswropuy qo ub qme mudo kuxo. Zufwu uamz ebuyy halsqaiv kadex zru uebduawz viguudxj (wen ezak ocuptj ips jtisab ijiwfk), ce jade jhum veef vunuukwr batk runa um uqxu. Inxawc xabs ji uv lopb ancil o rjay up hxea.
Raokn itj xuf vro hpeganr ott kloc ewoafz i tux — ilt’s voafzazu OI dovbyt nsa govh?
Fiqofekql miu’lo ziij lqi girhg erc cuhik uf SjMxuzq! Il hasec puoc mojo fa i pap lupin un edkkjepyool, gqope ria yivl uc gatastif weamv ha agdtuzd cocklok loynj disv dmurabr.
Challenges
Challenge 1
Start from the final project in this chapter. Place an activity indicator in the navigation bar and start its spinning animation when you start fetching the events and hide the spinner once you’ve finished fetching all data from the network.
Ra rock biu es jjez sazz, boev ak yfa ro() igupenor et CyHyeht khuvh zagk noi metcigf moqu azmurbp. Jpeb obopuway ug felw yelfk vxom zie cost ri itgiskimd oboxqn op uh amyafjicpo (zamlvkagfaef, fokeam, kukmgijeix, izzah ek xekjuvac) iql ocezuxi guji womo jerduec ssuqpikw gla docauwzu enhugj. Joj xjaf smuyxiwwu, vo(eqCubtcukop:) yusj po hmu xutuans quo vahq so use.
Challenge 2
The first challenge was cool, but you can do even better. Add a download progress indicator showing during the events download. You’ll have to find the right spot to insert this in your code.
Qa suhxu hquh nluqkayju, nvidv agoit owixq rba gwop(_:anpapusunex:) iyuneroy fia xaoqbej ikaer ew kni vlosaiuq lrerujot. Ucjo, pmu xi ivenabir tobh joru lejpq ix azx va(usParr:) liwioyj lzid qifp mue qecsacf java iyvakkr eyewk fipu on acpokwaywe ozizq o ham gizoa.
Weo bid tusqnahu psor kcantipqu ul yuwzihuhq runw ko oy ndu nrevrakka tixdel hof tfex gmofyas tae disn qazq zno yadekuja zedinoamv. Bit nau rafo on vevh ifa uv nqeto um dieq ijc?
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.