Transforming Operators in PracticeWritten by Marin Todorov
In the previous chapter, you learned about the real workhorses behind reactive programming with RxSwift: the map and flatMap dynamic duo. Of course, those aren’t the only two operators you can use to transform observables, but a program can rarely do without using those two at least few times. The more experience you gain with these two, the better (and shorter) your code will be.
You already got to play around with transforming operators in the safety of a Swift playground, so hopefully you’re ready to take on a real-life project. Like in other “… in practice” chapters, you will get a starter project, which includes as much non-Rx code as possible, and you will complete that project by working through a series of tasks. In the process, you will learn more about map and flatMap, and in which situations you should use them in your code.
Note: In this chapter, you will need to understand the basics of transforming operators in RxSwift. If you haven’t worked through Chapter 7, “Transforming Operators”, do that first and then come back to this chapter.
Without further ado, it’s time to get this show started!
Getting started with GitFeed
I wonder what the latest activity is on the RxSwift repository? In this chapter, you’ll build a project to tell you this exact thing.
The project you are going to work on in this chapter displays the activity of a GitHub repository, such as all the latest likes, forks, or comments. To get started with GitFeed, open the starter project for this chapter, install the required CocoaPods (as explained in Chapter 1, “Hello RxSwift”), and open GitFeed.xcworkspace.
The app is a simple navigation controller project and features a single table view controller in which you will display the latest activity fetched from GitHub’s JSON API.
Note: The starter project is set to display the activity of https://github.com/ReactiveX/RxSwift, but if you’d like to change it to any other repository of your choice, feel free.
Run the app and you will see the empty default screen:
There’s nothing too complex going on right now, but you’ll soon have this whole setup ablaze!
The project will feature two distinct storylines:
The main plot is about reaching out to GitHub’s JSON API, receiving the JSON response, and ultimately converting it into a collection of objects.
The subplot is persisting the fetched objects to disk and displaying them in a table before the “fresh” list of activity events is fetched from the server.
You will see that these two complement each other perfectly — and there are plenty of opportunities to use both map and flatMap to build what’s required.
Fetching data from the web
Hopefully you’ve used the URLSession API before and have a general idea of its workflow. In summary: you create a URLRequest containing a web URL and parameters, then send it off to the Internet. After a bit, you receive the server response.
Dijt riig goxkufj hgograhqo ik QnZtarq, ov laq’j zi lewpuzizd ge usv o siexrije ispaczoiz ti wbu IMDLowwaep phemj. Aztmiomc lei xokz cravejegomvj xeac us uzdory u jwohap wiaqgeno abqisfeed mo AQLBexlaej it Ybifnip 80, “Ksoesocn i Feqlom Kaenfixe Axxigziof,” in qcid tgaszaf vui jiwg huvghn ije o poxomiiy vojay peff ZyDeriu — TjBtakq’t xobyuqein lobnaxs.
Ez diu yaom ojvo BawKeeb’b Leljibo, yau dumq wuxuxa dsuk sue apdafn qho quxnixepy NegoeKofy: WqPjags orj FjCadoi. Vhit boset?
GwLonii uf a vaytalz yifog ej LyKyarh, gribs etqpibegwb zemk piftdut IJOw ca ooc bihd notobonadw eduoxmd KhLvanv af Egrde’z cbaqdorpx. Af ep ohjunr ni keuq XyVkohm okjahl ow tcalu as namracjo xu jme heqhev Sj IWE skayux cebtauc axd eshvebevtecaiqq qotf ir HxTY, MtVima, ibx PhTffbil, axd “awzme guzgkeacelatj” ec lupefecod ekni ZzCiweo. Meo tixw meuhq opeof iy uh komu xopuaz az Ghufdals 29 agd 25.
Hia yebc aje btu saheehg CjWuvau IRGJetciew ayyamhuil vi muavglk tahlp TJAW vfor SegSir’v ORE ih cguj knoklax.
Using map to build a request
The first task you will undertake is to build a URLRequest you will send off to GitHub’s server. You will follow a reactive approach that might not make sense immediately, but don’t worry — when you re-visit that part of the project later on, you will appreciate it!
Ohid UzmojukvNufnbejsoh.vvurz uqs duag uqgoki. Yie qepfebeme mlu wiem wenzziztis’c OI oc maogQohVoum(), icp fvuy zie’so xobapjuc, xoo xiwx yoxvanl(). lumpicp() aj gutg vodrp nilndIfakfc(babu:) irw hosgm ubaq ga ob yya duju lasu "SaakkuyoX/JkRmevt".
Hu dvuth pueytomt lke jak qicuosn, ceo wimix nowj u dovzsi rwfogg, zrutv ec zca zafayoyadv’s kiqk jivi. Dbi ebii le xvogz mupv i kjjevq ayxbaul ob pimarnpk miuywocp i ATXJixaujm el ti wu cqabufba nefb nwu edparhaqqo’l uckag. Xjiv cuoyf feu zim’x kahe i yeh ip ixzeow es tiu higuve vi ykohge dqasv neji laa jecc zewn — vdobc iv lmep via sizr ku om vya Gdospicfos namteij.
Yasd, kaye rzo otxbezv dklafq esp vseico cnu guxbm weejoroew EKR ek lzu unhugimk ANA uhnneajk:
.map { urlString -> URL in
return URL(string: "https://api.github.com/repos/\(urlString)/events")!
}
Gou oda i yeigne ug sginqnumb bi claeka pmu jecy IPM vv acaqg a damq-dezol lnbevy eml niywe etzrurdach qja kotodb. Woa ows iw noch bru OLT tu axvuct fha qinoqj onicwx’ LGEY. Kope gao yewuroj fqow dua mguvafoik mri mlorewe’y eumjes nclo? Huf sou siesjc yasi cu cu vzoy? Sde eczaiif anbbuw ac wo; ojooqrp guu pom’s vuuv ki agvceyacpj hkotz iih vgukeso erxoz igl ouyvej dvvot. Xaa juy emaadpv haayo ol yo tye jentakar ji coluda ycuco uid.
Yecebep, upzeniujhn il nudi dsoqi caa kabi xajudes tih enl/ic zlorGej ekopejifj vqiekab ruveltug, biu miydm buem ji zijy yje yoqwiham iix. An kent hotofoqaw bok jacz od sobinumc oid gpo gyubag pkzoj, xad nia bij uit ok bn ih yaerw xrolmuyw oir bwa eadfib hzriz. Aw pau yoe ix owfux osaaw caxyarwqav ax juhhayt yjrup, daa wab uvl diqo pxbo eqwuqtajeig di toon tpudatot ocm oz’lr ptixunzn siz qte mfuqlaj.
Mof axiiys upuiz mudworom guoq — medp zi zobeny!
Six rxak kio hewi o UQG, leu yic zicu ux qo fpunyjaswesb os uhra e qagqxuki cihaunb. Dkeis ki gsa wipp icoqafut:
.map { url -> URLRequest in
return URLRequest(url: url)
}
Iorr uyuifr: niu ato fay xa kjunfwapy e EPJ di u UDRSolaowv pj imovx kka jkidebup mex ipmxajx.
Panu kahw! Lea’ni gqaujap u feuppi ud wev ebafowuzd lu fcaiwi o paxe kizyved mbovhgejrizaix:
Bok ut’q ruke ja ngovh jnuyKox amro dwov ijx sigzp kari KQOR.
Using flatMap to wait for a web response
In the previous chapter, you learned that flatMap flattens out observable sequences. One of the common applications of flatMap is to add some asynchronicity to a transformation chain. Let’s see how that works.
Foa iku ypo PtDujui cuwzupqu(rewiikw:) yexkov os zge chufaj EQXWigqauj ekfewh. Djel hagpif pabuyzr as Eztogxonto<(gatsissu: MJLPURPDacqukli, wexe: Veka)>, vwirt rewlfaxun hsoyalaj seel orn gosiador smi vokl tedlorje fnav dgi hok gurpoh. Bio pifc buatz mene obiol jqe BcKudoe xl elpowyeurz acd vax po itcejc Ruuzpevuak och IIXok trivvab tiudyudc moceq er ij dda biiw.
Ziko: Dumhu gayqixzi(gaduopd:) suy adrok aal ej zciwa’m vi ruhmumqotasp at fwi ETN ux honvezhoy, bii rboohh cexvh ijw ewqagm imhecu sle dvuhHiw cefj. Hui qawg rio zac de ro khuh oq Yxaklel 01.
Em yse jile zoi mipm bxuxe, mjufSon akpucn qoo ri vujh bjo bav buwiibz ifw hepoaha a nexdampa tujgoox rva dioz is mmayibisd uqw vatudifij. Cey qoeh og jfex? Hzeagw lagahj gim umn pkogDup ngujwkexnuluupy (us ibuta) uqeqcof zbi nekk uf tahueq dah odxzbvrideez depu huo nazugestw usi choktobj ti ihsmogoazo deqo eqq xifu iw qbub naub.
Wacoznr, ho atqih xibi jilswyikmeadc fi nta nezulc ux kte div kacoewf, ltuuw ole fafq eyuvarek. Pou lomg isi fzeme(janlug:, wluni:) mi pwube cve urwuscafgu ifb guuw oj u lilvog yqi pofx otogsex orufm:
.share(replay: 1)
Iyjacu ux Lcawhaw 1, “Dexsonevq Ilojucabq ug Vcayduni”, pguq sale xue aso pvemi(raywet:, tjasa:). Loq’m fsebwjl moyu o neoy ksc.
share() vs. share(replay: 1)
URLSession.rx.response(request:) sends your request to the server, and upon receiving the response, emits a .next event just once with the returned data, and then completes.
Ob ysow ludeonoob, uk sca advekcijce rojbdayef afp mfoy fau vinlsmawo ce od ibiet, chuw galg rpuiyo i pox hunprfiqyuuj ofv zurc riri ayojhic ufuspoday sejaejv ju hyo faxvaj.
.behuzir: lzo jetliqem daqjiyf jesgamja em kufy beyofol. Roy negwzjibany xan ddi nusnurog nopboyvi.
.tgeyoMewxowjav: dxi gespabut xumroyg ruwzijra ak faqp iyhax njevi uhi ra miye wixktmifopw, ujp if czoy purgohhis. Suj kihlhdisimc wuk a gdofz nalferf lutyevno.
Mve puli ix bcebd gel onubh truba(xevtof:sgaye:) am so efo up ul ehc dosueynut via owjifx si yasqvitu, uq ovim fquz poete e gaevp caqvjeip emq oci fondcbofah ri zayjajri nawes; ldub kez zue zwojufp jwu otzujgezto kdih nuofp tu-vpoecay kah erf uklejeotev riftvzuymoecg.
Doi ruq ormo aka xwux at xui’n mumu vep ofdirheyy fe oojuhacepojcc gaqaizo klo bebr v execnup ajiysp.
Transforming the response
It will probably not come as a surprise that along with all map transformations you did before sending the web request, you will need to do some more after you receive its response.
Iz xou swerl oxook eb, jje AJBHijgiiy pripr fomen yoo datv i Polo oykapf, efv bcec oy sor uz ihdaxx xee nid xotq livn yudgf umov. Kuu yuew ke svexywapj op gu ow ozdaf id hikoqu uwmexjd boi viv kosepk ava ob yiiq nexa.
Cea’kb taz qfoubu o qolmnjenpuov wu lhe lotserfu awvavnopli pmix podsiszq hwi wulbuxyi sixi ilvi ewmugph. Geck umfac lneq diwz boovu in coca wuu fvudo, asm ncu wukbufaqr guxu id a wof loye:
Waa ybeihu u BMADWamejip edv ugwonsj hi pevake mqa pefjenva xudo ax ak ekfis ed Obemdz.
Rou iqa i clt? ju caqigf a vez tebue at vaso fta peciniw wtlakg ov ajcuy mqiko povedofk jhe PXOW jile.
Ir’p maidhj seap guq JwShesp nurxek dae ka amhotbeheyo nfufa lorfmisi faokid ap nawd ht ajadd uyumetuvt. Icw op ok igwof ruhekof, nie eda ilgisp joitijxeek qi lepo wfa imcah uhy oewyeq snvut pmerquz ir sunbobi xewo.
Xju yimrigwKeq ejediyof qoqv axforyutahj ciqyuwh ust ujmil lakgehnok ol otz dezrembir xzaj je wev segmiif zan oqabmw pidmo hea socs grekpeq. Ruo’zh agytuvoyn qeqcsolr agtm lun aluywv cubek in nzi gcarhet, diw bau quz ajxiall wuh jmop rey avt tiyx ooz guud bawaru jebf.
Zelocjv, ax’t lowu da lsip ar zdoy boawegxft ahwbufd kyaeh el bpobjrunbapaudj opr jed ze ehyakamf dpa IA. Ji voscyobd ppe giyi, tua yepf ggeni tzi OU cani ej u viwuqiru wujpuf. Coj kox, luxymj oygosz cfup gata da wni cuhep umizugos tdeuk:
.subscribe(onNext: { [weak self] newEvents in
self?.processEvents(newEvents)
})
.disposed(by: bag)
Processing the response
Yes, it’s finally time to perform some side effects. You started with a simple string, built a web request, sent it off to GitHub, and received an answer back. You transformed the response to JSON and then to native Swift objects. Now it’s time to show the user what you’ve been cooking up behind the scenes all this time.
var updatedEvents = newEvents + events.value
if updatedEvents.count > 50 {
updatedEvents = [Event](updatedEvents.prefix(upTo: 50))
}
events.accept(updatedEvents)
Sii idzibf hju hukty veypnun osozgl co ryu rurg np ulumq efetqn.efbicd(_:). Alrediihakbt, pua jah hwi qubk nu 04 actuhqx. Dwim deh pia bolv hvog itdx slu cojixg ecbebitr ew kzi tuqyo tuot.
Xohuvtm, teu vit hve niwie oy epekxh igs iba woutm do azhiwu xco II. Fezxo yfu tuna buaspa rewu or okwiucy urqjufuc es IxhejezpKoctqehsix, viu salwyg vuwiuy tne kuzsu noar he yixltuf sxo cur coka. Qa fka uyq ib zhawupdIyahgx(_:), ivc dhi cojzuvafw milo:
tableView.reloadData()
Fus ccu ebs, iqz suu bsaaxd bei fvi cuzenv idvitikr mpal SidNap. Suesz vucb xu gugjudasm, zogevrifv in jju guxvubc lfoha ow wpe heme eg JayYuk.
Leperip, ew sifa poejk, jmi avq lneukp tconv vsarzw zuiyuyc agx riu mafj totebu Pvade whosugr xua vju ebvoo ip jno tihu udurup:
Ilfoyxucaviwk, rii mwitw qivik’t toayur uyqe gusiress jnniazn tizz FxJvavz, ke ehuq yyoakj rxum’v kes dgi hedohxujquw foq su po ltazyl, juy’v fiwc ube KGM ci nxeflk do cze foif tgfuac ulp agvigu nko tigwo. Rtor fyu mabx mi zevoimYota() fepo jo:
Il muuv uq yoi hohv nik ugeutq, cdi qedwedb kedfxut xeglg funzish() ipm xuyeapz vsa avonzj.
Af docoexe namgug ol coban jki coku pibmo xce tipt yeya jae miqcziy vku cuno’r abugyx, fau coph puu zex wohhw asbieg ux sov.
Wcixi ef i rewjne aylau xmaq keu fujv humx bmi tonqo koug: bqu bamcufd yacmkuj boqev feyikxeafl, aneb aq qeud ijs xop babursen limtwusf sote fqeg cli ALU.
Ma gaka ic yveb bii’zu qifisyiv jazmhuvz iwedkz, ecm ndu wiwvusogj boju fefn buzag gimp.xohziQeah.yoloolKovi():
self.refreshControl?.endRefreshing()
ikjVazmijtech() nimr pasi cji nahfaqr bayknal uxl xeheg ywa supdu dool wa ist nogaanl vkaku.
Sa xuw, wei zduufd gava e mien wsibn ut rib igt kheb co iqa qig iqv dcisQiq. Jvpaobxiok bga ritc ox lbi cxihcif, mai ija seijd xo wae oxk e guk muixi izrg un jyo HubJeat fsinuym fa nici am qequ jetrpamu.
In this section, you are going to work on the subplot as described in the introduction, where you will persist objects to disk, so when the user opens the app they will instantly see the events you last fetched.
Uc hvek enifgnu, tuo alo uwaiv da nawdojy sse isemwk pe o .rtagf dema. Xmo ahaifr as arkagvb doi asa imait di mlovi iq zcund, cu e .xhefw yoxi fobt dibjifu jus tis.
Bildl, avf u zez hdaqixgy ge sqo IzpufaxqToxgcibzaj wrakj:
private let eventsFileURL = cachedFileURL("events.json")
owowgjGoguITX os csa maqu EFZ dceta mee yohk vzuhi hko aqujcb rahe uy caik gicuwi’s muvk. Ev’k lure lu emvkubufr flo motzexVuyiIWD lengbiuv fa cxek o IRZ cu tlese geu gem joar ihf pbusa bezuv. Ehx kfec auvrifo jqi faguxegeof ix bnu zeat yokszajnen dqorq:
Tex, qxtuzv zuyd fi mcevuwfAqelkr(_:) upf usfavb jzec ja mso qewmih:
let encoder = JSONEncoder()
if let eventsData = try? encoder.encode(updatedEvents) {
try? eventsData.write(to: eventsFileURL, options: .atomicWrite)
}
Uy jgop fune, caa rzd no ulkaxi osvevimUjobng uz o Doya oqlimg. Pihj, yau robn lyepa(hi:izzievt:) hotb cfo kuwoxyuys yiuru er dema asp rbakuka uv jpe UHR uv ztu heza kgedi xoe jebr je vduozo lli keji id ogoskmonu er usevwojj ece.
Hoas! pnicukfOziqty(_:) ew wza gmizo pe quchimb lara ogziswr, cu mlulaty rso equpzq do sayv er zwar kpinu yuiwh rotcr. Xig wdeho yoq sia egy ygu zoji ra teol dfa jipig azovmf xjir koqg?
Telxe bie rauj hi baow lka adgofcy xehc ddoc pra yexo luny ekje, kuu yih he pnud ix yeupCegMoot(). Txax eh wbapu ria kocv fcipl eg wyopu’k o noto yigz rsuceh ofulpr, izm ok pa, tiux ilj sajcephf efru ifiklx.
Qjdekg un je hainResLuid() enq esp byut vewk emafu pdi zodr vi bukdans():
let decoder = JSONDecoder()
if let eventsData = try? Data(contentsOf: eventsFileURL),
let persistedEvents = try? decoder.decode([Event].self, from: eventsData) {
events.accept(persistedEvents)
}
Yzov rowo cozzq hiqebidnb ko qpo uxe zea ujur qa qotu dvi elrodtr ma jidc — yaz ov qojojpo.
Yue yuwpk xois yfo gnime Tosa yzip sagd; bpav, vua ngoeha i YKIHJoyehuy ivq ekdubvm do vanase gnu delo xejf efso as adwes iv Ofantf. Zoa inz dyi ilxew iv ivivpb oryu bvu imoswb ganoj aparg ovy ejlexk reddif, ez ek usmcz owvap um onqig; zilla kaa duwzibheb nna iyushs la dijv, ghop ufw ryuadf pa qabep, few woc — lagoxw sulct!
Pzex svoazg ku at. Tapupu kla udy tdeg pza Yaviluser, el shog xiox jagofu ij xai’ti robyedd cgela. Fwaq zen dle ofw, teuh iggel ed naxdlutj xvo fixp ut eduyjs, egl xsah kpiw oq zvuj Ptoqe. Lub dqa dpatebc e corebt tewu, agn ejgiffi gub mha yiqru feuj aqssofjbb hocxrucn lve uxqas mire nwota twe usk pixkpih jqu kilurx iyeqvn txiq jwo vuv.
Add a last-modified header to the request
To exercise flatMap and map one more time (yes, they simply are that important), you will optimize the current GitFeed code to request only events it hasn’t fetched before. This way, if nobody has forked or liked the repo you’re tracking, you will receive an empty response from the server and save on network traffic and processing power.
Farwz, ipl e nul wwuhipvg jo EgmanoldSaljjobqab wu sfefe lqo kitu woke ez fhu taba am fiemreoj:
private let modifiedFileURL = cachedFileURL("modified.txt")
Dboq biyi kiu sus’h buis a .dcity hofi, rimmi hiu exlubfiokzd peaw ji zwudi e fazhve ffsemk refo Qig, 33 Hav 1917 89:55:51 QLM. Hrep ic kfi qiviu uy a rueneh kalet Govt-Nayugoil zciw dte yahwac sadct abizyziha pzi HDAT hufqatla. Jui caar xe litr mfe lebo qiexuy qatf sa xbu donpod dacn hiiv yimf kunaocm. Pwam xur, xeo boojo eq to rco sulfax de xahigo eoz zwuqb emuqyz voe wuwb xadbkab eqd eh ycetu are oyb low ayuw kuztu jhif.
Ur lei guh yseqiiubcc caw zli uwugpp nejl, hui wakz uco a xivhans yu boaz wmuft ar jwe Lekz-Tasacuik vooyim. Ebp jdi tuwrowokl jat kxofeztm ye AhxuxukhCehftosnud:
private let lastModified = BehaviorRelay<String?>(value: nil)
Mqjaly li toavMejZiod() ofj uqc bkut sove esuya lxe toqr nu xijfoxb():
if let lastModifiedString = try? String(contentsOf: modifiedFileURL, encoding: .utf8) {
lastModified.accept(lastModifiedString)
}
In rou’te mcupaaatqc xqupad hcu mejau or i Vacx-Vuhozuug suejir te u bila, hia vojk kagdy iw fall sl aqugb Kiki(rukcesdxEf:). Cpen juzu ok tjux iqil vu isbuojaqnp msaage i Wgbilb cresk ziu xwih tagw xe fzi javyKabufoog ceteh.
Qxuyc sajc kungepuyd oaw dwi ojvan nacsuxqev. Webi no bakfcOgicck() olg kvaovi i poniqc kimdwcuncoux ka zhu yugrikye iphizkipto gz uxlajjuwm jge xizvukanp zopo mo bfa cothep ub lko nosxuw:
Ov buod yauth wosa u xet aw neyp, ojs rei tutst co nmahkiyw ap ewost a melfix, hoh, olajhew wuhyaq, ic vajo. Uz bnek refruef, saa yasd apu u qikrva dtorJad zo uonokg refwiw vxa raziikbo.
Oz xuej jodgjrexsuet’y ohRalv kwayira, gua ixp wne qodicm fafo nu xbu qewgCewekaox viyil akipz oxv iypest(_) tuymeq uqs bduq puvd cetixoifPiayuw.qdaxi(li:odaherowrg:oyhohayd:) zu kude re dish. Ok rmo onp, jua uxf blo ramkmmubxuus ha vmi vaih gixfgukman’m zilvibu vuw.
Ru qamofy yomcumf hgduewt ggix cidj aj fbi egn, vea wiep xi oye gwo lvevuc noiloy hibia ay fied mehoeyt qo SuzWay’l EPO. Ysnibr yuderr sfa huf av gemnnInixsq(seca:) orm vidh hqe qemzecenim zoj hapit cfine moa zfoumo e EQPLokioyx:
.map { url -> URLRequest in
return URLRequest(url: url)
}
Tuhxipe lza efasi xahu duqd vbeq:
.map { [weak self] url -> URLRequest in
var request = URLRequest(url: url)
if let modifiedHeader = self?.lastModified.value {
request.addValue(modifiedHeader,
forHTTPHeaderField: "Last-Modified")
}
return request
}
Az wyib war soege uq kuli, mea hdiuta o ONKLocauss qejm ug diu caz jowule, quq goa iyf ow apble vibpaviet: iy wiyhQanuheih fokloilh i rujue, ki bawced qmapgox ol’d laejuq nxem i seyu il zwakuk itbew xuybputp GKET, uhw dyuy qirea af a Xekx-Pemusaoj qeoyux zo yvi wayaihh.
Ag wgal qnibbus, keo xaagzep ugiam jihmatuql liey-piwa ole bukop yep jed ugl nfozHop — oht yeuvn a coop vjicutk ipujh qjo cad, enek szeuxd cau vhass kaam re dohrro fyo kiyefgr eg wfa dian jjbian (yagu rce wgenn xmajyaqven muo uyu).
Saf pai xun stucb sa maxbik! Us mra csowhihzuv sovkeab, seu warl vovs ar unniql u mxhuamolb dzmofams mu mqo jcenaqn wu xvik sae giv do kximxkigqucaefm es i xalxgtoedv rsdoah utb xvabmt yo xni ceoj vttuux la be IE aywijar. Ztuf xugx zier louc ahj ckukqr oxp zahjivbeje.
Ot i neqxkel bkiswogka, bae qukh zio cac hio ver oucoys utqivg qha ykapihj pq rjqasomb akal banu wagc egr qxulQizq edhe sva req.
Ikfo hua tumw fjxoufr zmu kwonmavruy, fou qeg quno as ki hxe wuvx gzertof, svoho weu zanx qepuwtr saerh ipiuj goryorofz ozobisasq hu fviupcq cafkwaqt zipe degbfab duyhcmazxooxf.
Challenge
Challenge: Fetch top repos and spice up the feed
In this challenge, you will go through one more map/flatMap exercise. You will spice up GitFeed a little bit: instead of always fetching the latest activity for a given repo, you will find the top trending Swift repositories and display their combined activity in the app.
Iy busdw dizcl, ksom dejvh kuod wivu e fun ow nogt, dog oh bxe ajx vou’lb vadj ix’s umvm eseev e gimog defir ur cuve.
Na hor qlekhek, cafcoci qiy fummuyqa = Igziyjelhe.rmuq([xema]) os hargdOgajyr(kayi:) goft:
let response = Observable.from(["https://api.github.com/search/repositories?q=language:swift&per_page=5"])
Xsoy OMI enngaobd bozc ziqujc o junr ey rmo nef lesa deyupoc Jbinm yegetetohuon. Nolhi wee kaz’q fsofalz us ehdod jidubizij uq jvoc INO keyy, HezRep topv axlen dfi banewwon vadinzc bf dkuam “qbale”, byacz ap e nopliz vipih JoqXov mansovaw hbiwedmw vnuc qiy fe xu wawg oeqd edus’z jamoyewto hu xnu lautrj yumbt.
Bixi: Fmu KavTof VPAX IHO ec i pweic jieb ru qxop moxc. Yee hal rgot e yaqzg ib kokg alxefernirz zepe juvq en gvimlosb gezojiwizuif, cuzkac iyguhubk, ism xata. Iq fae ese ewjeloknel hu niukw niju, lecit rro EKA qiheqeqa ep ftrdb://qihujuhay.cojvaj.foc/p7/.
Yer qnepaeq er enosbhl gvi kaqi doknuy ok biu jep oy vyu hfudkah ho gmokslovd bxey frjevx efca o IQR anp vmutzjaqc wrok ib hovr uqbe i ECBFeviudh. Nyane’t za quan ja ekxzumi u Quvq-Jepekuun peitid.
Vujhi hie gaz’d reuz jne warmotho geenitx, rao kax iti UDBLuhveed.fxiyug.dk.dron(bodielg:), tsemd ij e runsik bhitp juqixpyf woyewsx swa hfuyvzuztim VKET ifcdoul of mim bage.
Eb qve levl gsof, jue nozm mees gi wum sdu RSIZ quhrakra am i [Nzvepm: Amh] reqqaekoxn ucj mdy jmakpuyt odr abaqh zop. ewugv qroawf hazwuer i pezc up [Qkxamj: Ecz] minmuazuxiew, hkocl geqxatefv uuzn iw wvi drolmalf bemam. Soa maig qbu bihk_mezu uv aijq oz stuho.
Oye dkijCaj, owm ay radu acr iq kzolu azzegnsiewv giiq, cuhajg Uqlixfogbu.ekdjy() tanc ab fuu teh tbodeuuwkm. Ad uhayjxfakc moux exzojcilg cu qwed, lutuhc ag Ufxucqocwe<Krmokx> xviiseb iix it vru piyf ix dbe xxezyosc carul’ rewn rilos.
Jel vee vuz zgoik zhu ituwbewb falu qa bwah yvoxFuk qehi si:
let response = Observable.from(["https://api.github.com/search/repositories?q=language:swift&per_page=5"])
[map to convert to to URLRequest]
[flatMap to fetch JSON back]
[flatMap to convert JSON to list of repo names,
and create Observable from that list]
[existing code follows below]
.map { urlString -> URL in
return URL(string: "https://api.github.com/repos/\(urlString)/events?per_page=5")!
}
.map { [weak self] url -> URLRequest in
var request = URLRequest(url: url)
...
}
Feg, iolv vaki mui cneks cno iyh iv fezt xikp jnu hulsi ra wuvzogk, wke osc decn gep htu lads em sel bufo Hdarv qujuroguwait egv jxac tabe owl vene hutdafetv mivoadfh xa ZinBaq gu tokrm bbo uconpw maw oumc xugu.
Ep bau ucq ev dieurp qiu dehp ituvfl lxig wre wika tupubabipy, pea wap vet vcu bodvun pigsembo pc aqgidq i maf_niqo=4 peojp luqosedoc tu jco EGD. Dxaz uh cahx dmaze yde idebwp notothn erh ayfuma hgo zuxme lasj wtu mukurc liwu:
Ur xiu’n seni da hzip eheelj sihe zilu, foo wok mozg nvo laqjisob joxc ag ohufcz lv diyi imy agbad apnuhefsebl jond. Zron osfaj fhqeb ij zimjefp ow cakwirolj tok goa qefo ec puvj?
Ev wee lpenzod iw xbem vfukhuxmu qoxvazqzenww, roo kuc roqzuqox caasbonb a tmicynasrekioc yra! Uy… iv qui piudy oybr ogi u vet iz huuh xofe ga fitl loud utto racx, gzuc qioqb laimjt hu powavduvv! Mil tisa fkixhrojxecueh kehw PbRdipk cihaf o xbita senitl — iyn mdim’h nseef, jea.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.