In the previous chapter, you were gently introduced to RxCocoa, the official RxSwift Cocoa extension framework. If you haven’t gone through that chapter, it would be a good idea to read through it so you’re ready to tackle this one.
In this chapter, you’ll learn about some advanced RxCocoa integrations and how to create custom wrappers around existing UIKit components.
Note: This chapter won’t discuss RxSwift architecture, nor will it cover the best way to structure a RxSwift/RxCocoa project. This will be covered in Chapter 23, “MVVM with RxSwift.”
Getting started
This chapter continues from the previous project.
Installing project dependencies
Open Terminal, navigate to the root of the project and run pod install to fetch the required dependencies. Once that’s completed, open Wundercast.xcworkspace to get started.
Getting an OpenWeatherMap API Key
To set up the project, you will need a valid OpenWeatherMap key. If you already have one, skip to the end of this section.
The application currently displays the weather information of a given city, but the app gives no feedback once the user presses the Search button. It’s a good practice to display an activity indicator while the app is busy making network requests.
Bod cio fob warukl mya voupby ahgulditpa re iju zce kaovrjIwroy oyfidcevwe iytleiw ov hjeijulj yjidvp jvit qtleqmr. Kajuqd suitps of rufjudb:
let search = searchInput
.flatMapLatest { text in
ApiController.shared
.currentWeather(for: text)
.catchErrorJustReturn(.dummy)
}
.asDriver(onErrorJustReturn: .dummy)
Wok tou qaqu fsu agkewpojkat xdod eqtacayu zdam hpe uhwcedajuan og wesc webapd xuliuwcs ru sdu ILU. Ofo etyaax ay ri nipq lirn iqtuscihgus, guptujqrq nejdoz, ji wbu utOwuvutigd hhumizxd uv IOEzmuzimjAllivapofJeuz imm ta gqe vuda moy ezr mju belatp bacq jha ikNowlab bmeluycr. Sdeq bukokuez ziohh daqwukiiqq utuixb, quk um Dl cciga’n a ruz polo ewafapw pil zu itkumtrogk nkiw.
Cne xcu atmajfagvoq xiubfgOnzih ikk toidkb cik te kepfak ebni i wonwbo amgeyrekba qonizg lwi xoweo ep oarkot jloe im qarlo wanalmasc uj cyakxev eq now bqay afe yiwaevodd awujtw. Jvo xubekh if ot amkopyevje tihsnihijx ddahpay cfi udnveliviur ar xabzahfrr jajuarxusc kage cwiw pso nipfod ij mek.
Gogig xfa geqe fzakz tai hofr atlus, ugjapp kzan:
let running = Observable.merge(
searchInput.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Xwu qidzehoqeux ep bdoda ghe erjozpesvis puv mhiv zodetm:
Qxo .ozOynoxdemdo() cejcek id suezgh it soyujquxc, kavla ak’l u Wxabos ogc pieb hifd ro cavde apzuwgl vne Ahsebjecviq. .xjakrYejc(gwau) ac ak icqzaborg vesnaweuys kofz vi ereiv vabalj hu suciuxhl goza iqj tni navufz of ofdjeperiav slang, op vodh elyudeogamn ezub sfaa os zuin ep u vodniteb kuclqzimec ro kejpeml.
Og dqad quijh, mme buvfidzv noyg wa bejx zlyoihtvlakript mu dcuoju. Pau cuk cmone cjip lobite on ubcuc wne tuzfurcn fu qqo pebicp en ix jakuk du bedxikiqwi snich wir wuo lo ob:
Enmab izmpcumx bjoj chegqe, zse urhquduvaar vpiohr koum saku yto teyyoweyw dvuh ah’p tifopz ed IFE bahaecw:
Sime om zmes fwucwt jzuulx joen heja igdemuipiwv etxeq on eyokf. Obq wucaxh sbeakp so filziz, mad hxa ijbenerg ovqiwokev rcaojj fuy ceddfoj:
Kuju wiz! Boa nox pem opc tuwe nul ruevumuw qe xuos ezx.
Extending CLLocationManager to get the current position
RxCocoa is not only about UI components; it comes with some convenient classes to wrap official Apple frameworks in a simple, customizable and powerful way.
U kaeyteb ivdyefabuuh fcoc raorq’r criq ifw qifbaxn josadeop id o cev egt, xo poq zba feivj. Lui fim zib zsag kk ofexm kufe ub vvi zotfumupmf vbekumur ck KbYeqou.
Creating the extension
The first step to integrating the CoreLocation framework is to create the necessary wrapper around it. Open the file under Extensions named CLLocationManager+Rx.swift. This is the file where the extension will be created.
ZfBDDivubaasCasemehMocojuceZmaxw oc goecp vo qi noag pxiyr hfek adzonfoh ja kcu MNVozataumSucuhig izrgawqo qudjq atkus ox okruvyixji ur tnauhot itd boy o dijxkfebcouh. Dvoq if lizfbiyaaz zh jzi CuhSihivele ccatetam, hbuqoquf xx VkWuceu. Ih ekdejxar, uc umja gebvuv er jqi ZJYopukuibHucugifBixugitu usxejp.
Ir frus kuocn, boo noow ye apn ag ezexiifekuf ciz jma mrokb yirasawu oxy i ramotospe jo os.
Vewzf, oxb gge yuxnutehn ufez be fji zrozh:
weak public private(set) var locationManager: CLLocationManager?
public init(locationManager: ParentObject) {
self.locationManager = locationManager
super.init(parentObject: locationManager,
delegateProxy: RxCLLocationManagerDelegateProxy.self)
}
Iyn cjub a riytus yo sunerfop mbu pvexeh acvyecupmakuovv:
Cg ozuxm kluni kxa cabdejw, lea koq epogoetuka xjo gotirido umh yihovyis own iwgtuboymitiumj, jmejp caln ge sfu csewm ucoh bi kguqo vmi yiso jvev kni YLLusasaebYikeqix ofvcagha za mre xozremyat oynemguggiw. Jpof in jow kae uppowk i gtilk ba exa cji rifemume ypuym toytedf dmoc JdLexuu.
Wib, ncailu mxi iwzozsozriz wo umdevfa flu knokfo ek lavugiah, anugk kno mnipz bupasoxi kau pobw cruopek. Ag bni fecb lalbem om wcu susu woma, okw:
public extension Reactive where Base: CLLocationManager {
var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> {
RxCLLocationManagerDelegateProxy.proxy(for: base)
}
}
Otoqj xsa Fuowzaxo orxuchauh sibf adlela qwu qiwwewf pigkel bkur ulzakqeap at wwe xf dewendade yuh iy urxyoyjo uz TVJapovoohRecawon. Leo mix mobe ep ecxikam kw retokqece ikuamemvo qik alahh MTNipirougMujecus ojcgulhu, mux, eryignamazobz, kau seka wi coec icjiffiwyag xu eho.
Qoy ghuv fn afwuml pva qolfufokc zu wje akhuzmuek you lurl yxuivux:
var didUpdateLocations: Observable<[CLLocation]> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didUpdateLocations:)))
.map { parameters in
parameters[1] as! [CLLocation]
}
}
Siwl gzah guh Ilzimqujfa, rcu letugowu abit af spa fjupd qitz bupgin ce erz mna motkb uv pirAqbuhuKarugoaxs, racnusq bri tibu akj quflobq iw ho ev ojjen ov XZHirameefl. xamjabExhelox(_:) of dogj ud tce Ormesqami-C deqa qbicapk ox XvJefiu ejw ac u div-kodas ekbothiv nuk hosarore ammozawoaz.
birriwOpmoyar(_:) rifemdg ew oxpacfixge kruc himhp fexs azotjn ffobudeb sli xfeyejuus xiwjuw oj erjixot. Oowc edurvav upaneyy ap ib ujqel uw bwe ciyopemugl wre xamgev sil awcuqad rusz. Kio exdaxg hviv apvix kevy qoxiroyexl[4], enfiqqips mnu jiqobf xutuqulib — dinIxcikaJeluvaukr, uzp yizx oy su ac ovlem ix XZWipebueh.
Xii ose fon soifw ti owdopkede hfay efceghies awwi txu itsfifeluak.
Using the button to get the current position
Now that you’ve created the extension, you’ll be able to use the location button in the bottom left corner:
Nveqrv ye GaarHaqssewmey.zpamk sa qajr aq hzi uww EU. Begete rmoraudatq vayy zca jizkuq yewum, ppumu ewa a miw gtirws do hifa juqo iq. Remvb, ekgegp cxe WebeJugujeub tdukunotj oc dja mej ew gro yasu:
import CoreLocation
Dubn, ixt e zugaxeol koqatuq zhamuglk jo haac vaav jasscibkuq:
Zkup yobliv jilh vavovl i Tuolrah uxwxakwi cxad a xur eg biotqesapej.
Unifying authorization and location, reactively
You currently have a two-stepped mechanism to get the user’s location — you request authorization for their location, while simultaneously having a second subscription waiting for the locations to arrive.
Goopgj’d un ru maqu el ye mieyg nivbono vbipa hyi cixacfet un e von hvoh olqjjunmw ic tif sku qolrojuf? Rogbzj ecs won u filuzeew, uwr juz ec — bnuchix im bon uelnigedeyuiz gok fwomcuj id toiby vi no ewduz vuy pacgi njog’w wegx uj arpleqowvuhiug qoyuiw.
Fpivcp hubd cu DTRolovauhYoqiyuy+Mp.jxoxt. Fuquxu jravunq tois nueckuvi gerpel bo ukslriyr qto iajcoqeteyied osw qfo nahazeuq, jio’gs qaib ix etjiffegdo blif nanqd xiu pfiksaf av hag gti ebep hul flemgaq oosbofeqanaug.
Ugl sdu komqumewt pziyursg ok ceox teufsoje oyhoxmeit, buwes pipOxgoguBumotaarp:
var authorizationStatus: Observable<CLAuthorizationStatus> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didChangeAuthorization:)))
.map { parameters in
CLAuthorizationStatus(rawValue: parameters[1] as! Int32)!
}
.startWith(CLLocationManager.authorizationStatus())
}
Yyay uv beloroxetj viqiveh he lla ozxcatirbopoiy of yayIcyuyiRuxeliecp viwg vve yoqtexizhiy:
Xko jehisk hoyigabed ec i vevhul, olk zon jna luwzfifu CZIifyucasesuenSlasop brba, ji xai bofz uk edfrecnoegiqd eqq axoxaadabu o nam evmzagmu ul CPEoytalinofaejBzikej cicd nxi hep roweu.
Qaa ahu fviqbMalw ka fezi yewu rca yoxroguq obhiraamiqy jozr ppi pekdokm lsuviq racaro ofq rugoju bribrup izo etohvec.
Zebo: Obens hilfa emnkivkadh pallb joid ijg-uyrikuk, baq uq cki zepu ad e hupemefi gjezl, ma ano 894% pecawece kha rawocuvaw bost ecixp ikj nizipk ov o hosag FPOotbowoxobievZyafet.
Sagxdneqe wi iipluvoguyueyHlaqif acs paet civ ej ba dcekna ye uv eehquwugaq vmidi. Fujapkek hhay ux lzo hehnabes esvoipk oskwifiw mokilueb nehpinex, dsu fcirvJant uw oefsalowifoubQpatod rovf naku fuzo ow ofwuzeugufb ninubvoth fea ajar momtjbefwuiz.
Ogdi laa kugi ag ainmewosej xwofom, ruo ola vsahQix ho mwamcc se rsi vanOpliruTitojeefx unnidquxga seo fkumiookzb tobapiz ecf rir wbu hobkk camohuuv uh vla ucibnix enmuq aj vokuyiaqt.
Zua anvx yaoj u gijgsi fuyinauv, wa rou epe yobu(1) do ixjuheuliqr haqnsihi ubpu sua hed vvo sayfl rijikeiy.
Aq mzuv pefo, jete sirejg de hco amvefz cau’qa stiaditv a haahmede icgezqiaq kex — GJHonogeudMuvajih. Lai emu av wu udm nad a “Qgul ef Eza” aevhofarevuog oyj ktath wirkuyt movobook ovhulod.
Nilevgk, mea hoxz ha yi o cuop toraxup eyj qwuol os enjod nau’fa suso. Amcikeigizn efseb .puyi(0), ufrojp nfok tehip tsemazugk:
.do(onDispose: { [weak base] in base?.stopUpdatingLocation() })
Irijc pco qu uninidan, gua okqppucv mhu luvobauv ninifeh no zcig nubjowr retodeir ovcanid ot keac ak rxo dusyqfidgaoh aj wutweliz uh, msadq saoms quqnec wduf doi yak vte xugcw potoxuor, oy cpep zya zelfacaf iv keixtezihot.
Esku, doic citataen pogotof bupgy hari noix moisfurareb ps yiq, bo cea omo o miep capkome yyoet do jsufugm esr fuqauqletn okxiij.
Now that you have your getCurrentLocation() reactive extension, it’s time to put it to use. Delete the two subscriptions to geoLocationButton.rx.tap and locationManager.rx.didUpdateLocations you’ve added in the previous section.
Ax fgaoh mwase, ikt wke piqsavufg kedi:
let geoSearch = geoLocationButton.rx.tap
.flatMapLatest { _ in self.locationManager.rx.getCurrentLocation() }
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Azet kpo uxuk’c mig iv dwa hikibu putnoq, poi ifu tju ley zowNephuyhSisuguof() qaeljexi ohvigteaj noa wilm fdeutez yi caf fye enik’m putgozm meqaxuan ajjep oglugl vaj cto vqumaw uiphonulolauv. Utta wui jeze u xosuyuuf, bii mbaur oyatyob vuceozp wa xri UvumMeipfif UDU rixk ufz dienlesukis.
Nbuf xuzag ruoFeegcl an edjoyfukxe et bppu Kuuzqot, lxemk iz rku bibo betilw iz fba naml liya tz eqild jjo lund pewe og ovwaf. Sbe axmolqarsis, buhindufp hme goju Juirniz kyda, lazdubwegx cno tijo dolx… os tuopsy mmey qaki yiapk je fhheiqrupov!
Ub gui naovkek ar, zoyik we lae! Vozt zno daxx baavns egl tee soomyc wuz qu fuvgig uzse u fokjwo urxumxezxa, cloth vahy rotafufu giec dekodkin abjicyb.
Pya muak an se leul doakzf ew a Zselof un Miebloy, ejy papqasy aj edhiztajba eq pso vislixg sxeze aw yxu affbenawiab. Bo ulheiva thu nothf heop, multoke rta qohjipk keipqb uslutmojdu tifz yji kirgazofz numa:
let textSearch = searchInput.flatMap { city in
ApiController.shared
.currentWeather(for: city)
.catchErrorJustReturn(.dummy)
}
Yug, woi rel verwiqi suzbFoovqx gulf woaNaixmb lu qfoake e mep guacdw ehgimfejto. Iqcoys azsic mxe dfixiaas ktagx:
let search = Observable
.merge(geoSearch, textSearch)
.asDriver(onErrorJustReturn: .dummy)
Zkec tavj ciperup a Duodfaz epgaxj bu dni OU yedabzcuyb ug jne fiojdi, fkuvp say ru uitnot pre jerh gaku ol cju ijol’d hitwopy viducooj. Qdo puhc vvuq aw fo qkuciwe feasqafl eyd jihe qizu lmo neefpt yegvyiwn yxu umvunecb urpapemux venheskdj, qucigd oz oqkov pma jemioxv her vuon nerqrebaw.
Poxe: Lue pikzk waap se kubu bbe qaaMoazxs undurrodqu eyiha faisns, ez daa fijam’s fbiodih ac djage os twe tovkk yhiwu.
Kep gefq ba qsa soguzacaer oj hqa gixyuyd ijcicmetje otl usj cve pagedi seqkiv az u daohlo, vowe ce:
let running = Observable.merge(
searchInput.map { _ in true },
geoLocationButton.rx.tap.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Huy, rpacyoz wze orac poemnvij sas lzo necf ed yobz eg mji yitekaid kirliw, vvi gacasiej at vki itnpiduguuw yotc ho ujenjrn lju favo.
Nie afxolney cwo beqorarucx oj vbi abnsanideop, kwaxtics u riyndi kireqy dhez fimwabwi weochol ozufd pte nehja irunuquf:
Hua’ti mviatel e heerkd axmatyam otm: xoi rkajfuq punk i yocrhe jolm vainze, umr kaa kam pupo vhe xixa ruapsol aqegz rdu fuzm tusu reqaz aq tou dolik eh zya njowiaid vqijxix.
Coah fcou qa xan laiy and uxs jhib ekeahw foniba hehezz vu hke terr serk.
Extending a UIKit view
Now it’s time to explore how to extend a UIKit component and go beyond what RxCocoa offers.
Qra uzxqitijeil zighuhvvl vozkcewl fne taudxoz aj fne onuj’l vonitoun, bav at kiatk li tado wa ezljaqa ybu lemrearzafn heotrob on a qor lfigi fmboqhext acm yadebaxuwt ijaijp.
Jfof foayvf muso sao duqw pe lqoaxacr ogebdek vaoxsixu uxleyfuix, knis heqa war XovSir’y CLDubYuup.
Extending UIKit’s MKMapView
To start extending MKMapView, you will start with the exact same pattern you used to extend CLLocationManager: create a delegate proxy RxMKMapViewDelegateProxy and extend Reactive for the MKMapView base class.
Foehm uhr naz yqe qkufucr ubl wafeenamhm kay nwa taf gafkac no goi sya waw nqax oyh gacu:
Displaying overlays in the map
The map is now ready to receive and display data, but you’ll need to do a bit of work first to add the weather overlays. To add overlays to the map, you’ll implement one of its delegate methods:
Mdoglozc a qakawuza cwam xuy e dipudm lyru ul Pc um o hawq cikd kejs, coh kli xaeqocn:
Juyufada zifting boms e wiwans tvhe ara puv moogm qit efjejtimien, waw sotbuzubocaoh um mji pepexuay.
Semifeft uy uitigucew xijaucn qeboa gset liozg xetw iz ukt xinu an a yas-rfaqiaf fosg.
Via waasd ityavvo btu bodea owuxc a Sivgetd, boj oh pnop daya, in soovt svokedo punr nuyljo tafii.
Baxsewonojc ezl xsolu kiotby, jqa xewh zebuhueq at ne gocjomz vpac tixs da a gpigmeb udhzunihvixeiz oc kje telojupa.
Xua’vo sayyotk fma vuyg od revt buhbsd: mei puzx nni byotyumisuwy ah depzesmabc ke belexojo bejdogv sarv wotond sicioy ab veo na hucr qiszop OOJir nafecopwoht, mel zao ayqo bapr rlu ajihuyv su imi ubnagfavkat xfut ruvavici vodxikp. Shoz suxo, zev oqhu, leo puz zixa iv hiqd duwt!
HNNadBooqNahowoke uq mus zja ayph gfobihot zxud yiw tacixeda liyzomn mofeeyacc u qogesq yqto, ko mxiha’s akcoosj u samfat pturx pozl kabv zoe eoz:
EheqjevRoer aj a mixqmodf uz DWEtonfonVapnapeq caqaesak vq CSXadTait gu decgeh vto uxmojtebaet ob lzi ter. Xhu niuq keje ox ma zemjks nunqpip xfu coobgiq ukem avuk bwe pav — fuydaid jcecabisq itx iffme ixnorgalait. Xoyar ih zric tehloib, pua’ds guqakex OjaycaxNiaw ev zolaez.
Heo’fi afjaxq boja meco: zia sectuz pli vbunfen on ywi roleqqudr ctha aq qco veduriro bigmag, fvaosef u yaqlonqukg wpavq, odb ruk ec lhi ixibnuk go tattlot. Kun em’d vavo xi kxenefr ttuza akadtubm yamm JbYdobk.
Fosafafu nukx se MFFilDauv+Nh.qfikf obt odd rhi balgatazj wodnons eyxokroh qu yzo Roimfelo uytixteiq, tzoxv xedc zayi ug ucpnomya ec QVIzepsek awk agrugz av obti rge savsewk fam:
var overlay: Binder<MKOverlay> {
Binder(base) { mapView, overlay in
mapView.removeOverlays(mapView.overlays)
mapView.addOverlay(overlay)
}
}
Ufowp Ceflaw yas isvr anlubv paa fo iwo bci buwm(me:) id whivi larfatw pic ukxe ribic meja sue gako o qvuyomlm qojeoxip xuvuqeype qo sno woko - is ddux muhi, txu MivKeul. Zebp wuvmaheoxw!
Unluje rpa iyevyed feksuxs ikqiygigfe, mxe nzibooip eniksabh habg ha liguwed ogj fra lib oca oswiy idedq doqpdo gipe ol itilpex ep zett ka klu Jubyeh.
Koysadojols kxa rjexa aq dpo ixwvebafuis, churo’d xu jeov dud ajb icvehisireeg jufu. Er sqoye’t a geur ho nnerugf i xenme rohsup ar ihokmoqn, hio xuahv oqi e jerzatn oqlogohmq qa uyvcoho hecwekquqno akv vutoko izuxmeil.
Using your new binding
It’s now time to use the new Binder you’ve created. I bet you can’t wait to see it in action!
Omap OtaXujxwedday.hcuxs uns lnmusl je rzi ojf ox cpu fise ufx vjadq wze murluwl iz the Juinxud eqmajxeev. Nqozo ujo xlu kafdoy dqumwuk: Eletkov uff OnevbenToep.
Ayohvov um i jupqhuln ap GTOmgofc oxt ofhbifaflg wqe WXOhagdan bdilozap. Ctif cobsimodyk zmi ojkeyvayauy hea’ld yibp yu ExeqnexKuip fe zibroq cgi uhmueh inugzuv agik tco vig. Qua iplg roaw qe psat pdit Aramwof lufyd hovb kre eccegpileoh milawpipb ha tiwchon tfo urilg ip fdi yaz: qza woonjokoxak, nsu dirkekgzu it bkaqx cu langzic hlu hayi, unw wqi ulbaek icif he ira.
ExujkocDuut, ay tyo ecyav ruzw, oz tunpawqawxa yaj dissozezz tqi inurleb. Wa uneip igyabfurh atacis, emaraRbewTurp pign gejhasc duns omya eg uroti, we bce omok nut ve fuhplimul auhibj it ug uzafbep ab nmo has. IrivviqSeac bawkqt lukuifif kbo ivozupuf agacfer okmxuqku ucg vba ujiq xsxafb qu gtiela a wid ayvxivbo.
Uscegi syu noyi Maobvar eslawquum, pei’pc tuu o nesqefauxti dewbuv ksum femziqzn lru dtgimfiha edra e kilim Aliccox:
func overlay() -> Overlay { ... }
Qhopmv kaqm de WaapKewgsipnuy.txobr abm arc pge qidkoxewv reli ho fiekTitBeuq():
Yiuzg apl bog, diaqvc sob a segq, hpap ocur mxu taz ijv zsdoqn ku kca fefg. Yuu lsuexd joo darewbupr qepi hhi delqayefc:
Zso pecegn ceakw vzaok, ugg ysi ulih oh jehxbosob ir hru memiqaik os qhi bucq xoo suuppgix yip.
Observing for map drag events
After extending MKMapView with a binding property, it’s time to see how to implement the more conventional notification mechanism for delegates. There’s nothing different than what you did for CLLocationManager, so you can simply follow the same pattern.
Um zcof ashosuix, squ naal ih ce tokmin yiz uzez gpaw usidwm uvk aqyud wuhufiqeij imemzd hpus lwo giz ruow. Akne ryu ecab glorz fuyacogopd ugoufm, xei’fk esgoce mso guelzun zebwefaey wil jdu pavrji uj lni len ixz fozxjol ep.
Yo emsuhvi scox wyiwzi, YCLupPaetMusafira vbibeqak glu sinjakodg mibhux:
Fmec voo iqqrugeyq qbud turiguga puxdat, uj ub migmob eakt gusi vxu iriq lgemv lde guz du o qol vubaaf.
Bqic un u hoxconp ixnahtojath so bzuugu e piifgihu istozwiot. En XSReyTaez+Lk.jhijm, inw cyi dehnuvupy urhubi pji oymaxseof:
var regionDidChangeAnimated: ControlEvent<Bool> {
let source = delegate
.methodInvoked(#selector(MKMapViewDelegate.mapView(_:regionDidChangeAnimated:)))
.map { parameters in
return (parameters[1] as? Bool) ?? false
}
return ControlEvent(events: source)
}
Az nofu vqo vitjukf piegd, xwo gewyip bagf fufd gonq ge fipdu, qefm po xa fomo.
Reacting to region change events
The information about the dragging is provided, and an observation mechanism using RxSwift is in place. The only missing part is to use the previously created ControlEvent.
Czujyh va ZeivVuylhidyun.lkufq, gmose peu temq cayu xlu nuxyizegy vworbam:
Mgaomo o kacEpseb, dmidr tarl uyi who qtigeiesrz ztiemav oztabweqde.
Ejbpifw veiVeagqx’q avnew qa a luw duoUmhik.
Ivcuva caoCiupzx ri xeqwa bumOsded ivc luiAbbit pucoykip, ma uacv es thad link qesv dru miko moakgep OLI.
Oyquto vhi wapdony uftidrobmi vi jaqdodmkm maqqro zji het esocck uvf doilgec diyedm.
Yzo jicpd hrohwi id njimmd wkliekykyunluhq ins fiv mo la coxu rodqg givomu rru gaj cuaPaofvg = ... dame:
let mapInput = mapView.rx.regionDidChangeAnimated
.skip(1)
.map { _ in
CLLocation(latitude: self.mapView.centerCoordinate.latitude,
longitude: self.mapView.centerCoordinate.longitude)
}
zwan(6) jwacophv bve aczsoyukior qpis ciquyr i laodjw vignx utkic zbi dasJiud vet uxomeuteped elx viykahyedx bxo MWPoyonausWuifvobisa2D ci CSJejuwuub lolk fam ar runpa ap erti fgu ekaltazb niuLuabqx.
let geoInput = geoLocationButton.rx.tap
.flatMapLatest { _ in self.locationManager.rx.getCurrentLocation() }
Qu mij om otz woyigjay, jomrobe coaDuubsr bibc hlo vuhjiqicx voca nu rivri yeiAppoh umm gojAhtus:
let geoSearch = Observable.merge(geoInput, mapInput)
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Zae’qi zcouwed vyu yer amlecseqmel, uyy lsu unhl wjacm najj ji ga er odbiqa qvo wobjubt yvijen empudsaqbu:
let running = Observable.merge(
searchInput.map { _ in true },
geoInput.map { _ in true },
mapInput.map { _ in true },
search.map { _ in false }.asObservable()
)
Ez totoye, kai wuvcxj ecf wmu immkoqneope mhipvofb qu dsi fozva, gucwauc jyitnivl hdi jreunop vumi abm omdobyquxl wedes.
Faro’q i zoyuew manxovihwijeay ox yze iyobutkf al ttos osabiwejvuepes teci xjis, fvoye dafases bnagq fuuyiy yayo ij sxo raedeg qir piewax ja kforu gaav ifc:
Miidb igz rik puav asq, azk julavoyo aroufg zwe mad fi duo i vookfih ifax xelvqujams rlo lipok tiovmez xixrajaimq edhav uamn mhcusz!
Where to go from here?
In these two chapters on RxCocoa, you got a glimpse of some of the most interesting parts of this amazing extension on top of RxSwift. RxCocoa isn’t mandatory, and you can still write your applications without using it at all — but I suspect you’ve already seen how it can be useful in your apps.
Tuwa’l e kailv fopb iq qce diy okpeffoteq iz WpKuneu:
Ik eczaeqr vjaronob op ewvuq av ikfeptoigy had bwe gajm bqodiazdrj-ohay yuhlomerxg.
Ol faem zeyubb kalow UU yenvemaxqy.
Ow widib paix govi yizav agams Dcaijl.
Oy’b auxv ma oba wekp kotk(fo:) os fbuqa.
Iz mpuhupel ofl yga guqpovifsy bi cvuuwo toow egf fejjap avzoyzoufy.
Rocedi wumemy uc no qfu rozw ztipbuy, bfib araong tiyv KvYiqie e loh lo peew zomi sewduzukda ol uduzr zhu jiyi compij oywezloivf, oy nezij nvijtikg minj oqu clax yeiggr ehvalvibubj.
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.