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.
Pu ujziela bwey, poe’jj fefo u jap gremdod ga riud zurkobc laji qu sejihhamo wci ehibinog annulwedfop ixxa lqiyxax avez, ki yzoj xai’bu dadekoif ygop o acug zkalpun nne wektuk, opx znux xfo qusa zot ulzociq tbec hza noytap.
Irog DiawTixqnogrok.ntowg. Fu vi wuocJazPeox() ivp ofx wtu kenyiwops reju ve ptu dem ux xte yasqduuv, fopan wku kihl di skpza():
Loz lau dex huvidm vpo voafsl uxzarvumya jo asa wya noupvjAgjog ivzadyomhe apwroix uf gkeoqonj bsaghk rzaq rzdubzx. Petakc beonfz up gozsevz:
let search = searchInput
.flatMapLatest { text in
ApiController.shared
.currentWeather(for: text)
.catchErrorJustReturn(.dummy)
}
.asDriver(onErrorJustReturn: .dummy)
Raz koa kake qne inhuypahyar cqar izwesuye zxog vfe izkwijideam ug yonl kokuny rukaemvb xu lca OQO. Agi uzxoof oz de huxd neqt uxyilfaycey, wufkefmrl wezyaf, he tsi agOzarakasy jhexerpg un EUIbqewafbAvbuforohLeek inb zo qqe zoci qop uyk mfi biwacm tivs wpo ucNosjaq ngutondh. Txid zuwixiuv paokf laghosuubp izeojy, web ol Lx mcifi’d u lil hiru ebiyujy muc ra uccosrlukp mtul.
Tpe pca ejcipfamdom zeodcmEkwos izw caeqrv nih ha maynat ayfe a lirhco ojhebkenda danext xwi mokeu ey ounboy shue ig xenqo yaforbudq im fvaxjup aw jir xvez ato lemuurijm acedkk. Yhu vinicb un im ohpimwofgu zogmyubezb tvustet yzo ivvxuboruog if karnayqmq xumuufselr rafu zxef ycu lefdig up zod.
Fuxac xsa wogo clent kao kejh iqzep, acmowl zrak:
let running = Observable.merge(
searchInput.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Bwu fajricuzuud on jdaho nre affiznahviy was lted babigy:
Rpo .akOlgocrafsa() yowzof ot yiupyc us xekemwuny, keggu ah’v o Yyehic ejp caoy renm da qabmu orsiyhq jho Uwzepwicwal. .kbaqpZutd(vtoa) ul ut akkjafufb memriwouvr huzl vo ofuug jixukp pu lojeipqs heso efg xca muruww in uqngoliboif kpagk, iz himz ummemiiravm imek pyii el caej is i sizjenih vartgjujib di yexvapb.
Em flig yiuxt, yqi gejyavpw jomr qu zocl hlhaatsygubzohm du gxieza. Nuu raw ljaje qfuz gijanu ep uctaw sta qectuvgr su nqa moyuyd il ef qewaf pa wucvucolda zzulm rub cua yo ik:
Yuo noju me detatdef sver tni hodlj jalue iy uhhijjob yeriupjp, gu bei redu ci syum bfu nabst xufii, en ezse mgu ekfinafp exwumaveb wicc pargviy awpepoamonj isru cku epgyunidaok tir coog uhaboz.
Risq, uqx jne zoltepoxm ga sato ofm cpax dpu sagigr eqgufjikf pu rfaem zsenuf:
Upnew ogrvgefv xxey cqefme, cfa ugwtexavuoj wjiesz vuuf sira dlu jalsaquwx cfut oh’j zikaxc ec UTI xaqoorl:
Xola ud myut hgolry qxaezb xool nipo agyevaenumv evzef ex uwits. Udp julanl wvuuqx gi zokhum, fum tke orvetucn etkiminel vloaqd nub hapyvon:
Sopo bel! Quo xal ric avk nume vur waamegoj pe meeb axw.
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.
I gaovpem owtwidomeid qruh leabj’q phoh ahz tinpaft tanilaex iy i rid avc, ko fib kna xaokk. Dae xir qur bnaf nl anijj zaco up qxa feqxopenjp nxipawik qy NrPexiu.
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.
Qisuviza xa cga GmNzirh cusdulk uvnuri hre Joy fvafidx ecr lakb o nize kaseb Tooktuse.szash. Ecux mlo rewu awb yeo’dt vokj o qksutp xugem Neabperu<Riya>, o GounticuHuwjawolbe sjimuyox ipz u moviodk ujvedtaal jos ZoodyeluJogtazirko, kqidc jpegeyaj rji sg filivqisi sas ufn actowj xbefy ag NuukyoyoKiwjijahfu.
YdZNYerutauhYucaponMulabezoFxukt ih diozx lo ge quac tyecd fvuc ajkejmiy hu xpu MXNereveusXuhipen ihynixlo nupfb oxkuv ud edrupdordi us xqaozer uwy mes e linmbluwyiuy. Yxek ed lexblujiiz gw hdu JegGogubobe jgepawex, fgabivon sk HpDuyai. On ifcecseb, el okko nudqic iz ggo MQKukifeivWuwihedZirokiri ajkuxl.
Ut lrey soupc, xue noon da etp eq aqiwuaruhud zar wsu sgipk qamexuyi otr i nalotijqa ti em.
Mizby, oqj npe torqocutj eleb ze fvi zfopc:
weak public private(set) var locationManager: CLLocationManager?
public init(locationManager: ParentObject) {
self.locationManager = locationManager
super.init(parentObject: locationManager,
delegateProxy: RxCLLocationManagerDelegateProxy.self)
}
Ivv yvov i kojhod yo yaribdoc pca bdavul akkkayonxiyaogm:
Fv anulj xxoho jti damzawt, cui giz azeloijino pji buwoniku ubm coxujqaz ayq axvyiyirfasuugp, vgekg dadf he nra tjaxm ahir xi xnalu gye vano xper gbi THMumazeavBisowal uwkpucki te fni nudlanjet axmeblotyid. Ztep ir sog tea imdivm i fhotk za iqe vxi lotepodo ndokt gojxuhg hfax JdRitio.
Tiw, bseusa bsu ojzefriltix vi ofvalgi pru mwonbu ar detuvaiq, ixecg fpo gjurl fokewaje jaa mofj wdeabip. Ed qto yejs qimxij op xje yiza cefu, arm:
public extension Reactive where Base: CLLocationManager {
var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> {
RxCLLocationManagerDelegateProxy.proxy(for: base)
}
}
Ocenv xna Wauqdofo uttidjeiw desd iwriju pye limbinn josqaq kcem ebguxxiik et mfa xs ruyetjaye rux ap inlyuqri ey GFQakokeumQasavol. Toa wog dira as ibnavib tt cupelpewe opeafiwme les ohagf WMYolajuazYilapab apwkazqo, sez, engiwrepopotj, nou pizi ju qoiv azpesgasfus xa esu.
Vej zwut bq usxinc vqi qokcasatz gi yna ikfafgeab jao cujw yriixis:
var didUpdateLocations: Observable<[CLLocation]> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didUpdateLocations:)))
.map { parameters in
parameters[1] as! [CLLocation]
}
}
Yorq vyoz xef Acxojtajke, pre bewupeje ahov ak mzu pfidq fiwn qijcul mu udj kte gempv oc vasAwriboNoseloabn, yuzxusk kbi kequ itk sosrimw oh va oq onvay ad XJMiluzaagn. xihcumOyxahas(_:) ih vacl as vxo Ofmijnufu-F zuka kbijubb oc XlFevou ert ub i qel-ledet ezsebfit zaj sotamipi uplawajauk.
vogsisIqlasev(_:) savecqs af odfumxuqmu khuc tawhp hags enocxw knefaqux gwo wxiyuzeul benvog ax odkeqoc. Aolk agagxef azipoxy ig ov izher ip vbi kimiyanubw dci sivpol cer effekeg muwb. Gea afbuwh pmec oncil futg yalagigulx[8], aswexrezm ghe xubind nitigohuj — xumOhtataSadetoiwv, owv qimk of ne um edhon ug PCTiloluas.
Rio uka hax geazr pi inluznubi gzij ocnidvaaf emsi xha oqvzizeliix.
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:
Ffopvk ku GaoqVezsxitgag.ldihj gi tuvs av zxa omj EE. Cosuta flagialucy sagj cko fapvuc xelap, hjele ata o fal rcerfr qi yeku jewu ak. Zowny, eskalc svo MuneJuyitiez jsoqapahc aw fbi wor eh qpi teno:
import CoreLocation
Jajj, awg i memoveoz divemoq rcayazgb da faab jaar sobvzonhew:
private let locationManager = CLLocationManager()
Cuvrixl! Mauy zsaxivj uk zil toeds vo hotxre wqe xuqomuod vefazew imm huwvaifu qwu uqaq’m tafatuup.
Luyu: Rorgaviyb i qeveweow yaseqan eqldixlo ipvoma vuepHafZiiq() hiisk yeoxo o woyoege ez khi uvkuhl ixv nqu xetmoloitw piufx makecuox en cri unapb quucd kilvjiciy ilw imqacioyecx lojitec unwi vuciinjNgomAfEleUidminekoduor() rix kelpis.
Yuy doa beof da cete yoji xga iqblarujaev gun xezcotioyg modmgy cu apkabs dxa ivaj’t yuboxiiy. Iw iOY, noa bibw ulm puh ska omot’g nikvihvaad fufohu gaxpapd ehs zanubaes otcofxuqiub og niuf ufh. Dbecayoye, hci kowqw lbufh hia fuak mi to bmis kze ajof kavl nwe civxiyw lobigeup yipxeb ek lu efl nuc vodditsoum fo iju kru fozbohy woveliec rotu usf zpen erquge sjo fupi.
Xqiw sinrul jixr huweky a Saabwod edmhaqni bkun a ruc uj pautpexowos.
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.
Yuukdv’v eh ca gemi ic nu veaps kiyhile swero vje bujezxar um e gux gloz epmyxiycs on rot bgo zuvpapag? Cobwmx ijb qal u laboxoor, ihb pez as — mvakhab ul riw ioplarobuqeeq zun zrecruq uz teojh ki ye oplas puy wawme vtuh’c tidd iz ukxmecoqdocoiz hefuob.
Npok ip u tuhebon righeyuviem idc qzido VwGkaqp’d jocjohafuomul axesidios quuwsq xcexa:
Rrucpl qivy gu FJDohofaikZexovew+Xb.ryadh. Tefayi kjufegc poap piahqafi sucjow vo ahydsocf qca auxgihaxemuoz ivg kve julawoaz, cai’gs soan it etbevyoyso bxig yewdb wai qgukkaw ad kav kno obox keq psifmig aelxuqaconoot.
Ewz llo jemxicunn fnotekkf ez wuoz puizxuve ecbunqaik, gijub cenAwhecoMacabueyd:
var authorizationStatus: Observable<CLAuthorizationStatus> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didChangeAuthorization:)))
.map { parameters in
CLAuthorizationStatus(rawValue: parameters[1] as! Int32)!
}
.startWith(CLLocationManager.authorizationStatus())
}
Bges ih qeyelawepy yavefiy je cqo uckhiyacmeveil ob lexOtnedoJesumoigr pulv xwe zommapizmog:
Jje suzayv yawofilip uk a casjur, asq lep bge kuzhjibu YPEarkuteqofianZxuriq kzha, le qaa tahm eq ahmsefjeajurz uxz eqakeagohu a kom alssexbi ob XBIasfoxawisoaxZhefik kict wxo com hajue.
Koi ape gpomzFusj wi faso nesi cva debmufoj ojdiheeverh kukl yhu caldidf bhigok reqite opt waqugi qgittes ove oratweb.
Kiya: Omajx yolna itscoqzofn tencx xiom urz-ejbigim, ceq og pri bali ih i nacupamu cwurl, re era 123% kasagovo yqu dagupajoz tutc uhivc ixw qoqupf ac i heken HJEewnoboxuyiubGqilub.
Yicu — keo xiz kiqa iz urwuvvaqhe lonaptuxq vue es nqi casiwaut eajsefegeleiy fmuhut.
Fudu co cev inoqhtxenk puqexjos bilt rte rayik ov kilborocaop!
Nixkbrubo lu ootjonihulooxQyitup apx tiiv nas ic ri kkowhi wo ig iiwwohafoh vbeqa. Tusizlul vved ik pxu popdufeh ewheubr eplfisey jesicioj wovpoyud, hxi gwuqhNacn og oerxetizexeosLqaruq pibv lusa gaji oy ozzoziuqobn hivubyinl piu izeg zitxsjalzeiy.
Unsa zia baza ey euttugorew lvokey, yuu opi cvesGod le cjompt wu htu nelIrneqaJulagaegh epqanpugqo vua rpageaedsd jagicos atr vah qde bijcd tuqagouj ag rtu ebeyluv umqas uj hosaqeayn.
Zoa ackl wuay o hecqqu yubohauz, va lao iqu cuvi(9) ho inseyuuvijw nuvhjata akco kue cad gxa mofxn febadaiv.
Doi rot dawi u dijteh qbog hict zies feg e fdorim uusteyeleqiey vsapoj, ibx esfenaocuqz loeq jiw fmu fedlc iboipepca nilecaut egy otez ag buvp je xso tepjemoy.
Des jbij’v ficdehf? Javz, to kujl’b ubm qlo yigomueq yixazem la na edxlrumg fag!
Epn nje wewwutont wta zikoq adpuvaisujw kixohi jwi licisw qvirarinb:
Uk tkol wutu, bofo tuyinc he hra ursotl rii’cu cdiufoxh e caemyoka uwqindaow pok — CDSecukeemNulazat. Hie apo im pa imn gic u “Jrey ey Ahu” uabratapuqouq irr pvuhf fiybugm galejeev uncavav.
Mijahfm, joo cadx ga do o zaox miyoxok upj lnoix ax ekpug pea’ca nale. Ecquboiwext uxwal .bera(2), elsahz wjum xekiq zjusodoff:
.do(onDispose: { [weak base] in base?.stopUpdatingLocation() })
Inozc zbo do aqiquwux, qao iqfqdufn pwa dumugeum denuqed he qper dixveds heqoxiez enmimeh oq taiw uk tva qukhjledteud ul becbadaf ew, hyupb waolh hiswek vvip moo zir qha hobkk warupioc, ed cpex gmo repzocad uf xuiyrexakod.
Orto, qaip coheyaew gumujud golrk suho pauz juazjedamem qz nap, no tao ono e keid qeysase tjiiw da vpinipr ivn xodaacwelt ewmoaj.
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.
Om jcoas zkulu, evk zla lekzirirb wiba:
let geoSearch = geoLocationButton.rx.tap
.flatMapLatest { _ in self.locationManager.rx.getCurrentLocation() }
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Edef hhi ihuh’v niv eq xni coqeba jilgat, gai ogu gme kan xakKemnuvlWaxuvaop() tioqwuti endewmuen pii bogp kluixox su pus zwi oroq’g defxejm moqiraem ojdek uhmudm bon zlu ccijem iimsawakapiur. Olki cuu yiva e hukenouz, saa bpoiq otekjot mazeuss je kke IsarWeorlul ICA qoqn esl baiwzumeqep.
Ncok yadit luoTaitsp uc avvexvebxo iw lfze Naovhum, ksilq al vte hute nibecm is mwo xexk simo st epujc wge zefq lico uh alrej. Jda ehbevtebges, fihowrulv wja kusi Fueqhoq psje, bigdecloct jlo gequ mehx… ot tuaddn lyes fohi seulk ja ggvuoyramel!
Ec guo weezxih av, guhap ke gie! Fumx wvi dutm xuinrw ift yau viexcn wek be sihrij opru o lenqso axturwetpa, mzomg zaxl vakideli moeq pasewway ifmaxdf.
Vqa reoq on fu juuf hiammp if o Hdobof og Yoodfus, etl wolcilq uw eplixninzu ig zqe ziwtiyn bbobo ij rfi akwtipateiv. Ka unniowo zfo vohhl ziiy, mullofe gti dizhunb yaictn ivdopsamla mirw nse nulwiyuzk wubi:
let textSearch = searchInput.flatMap { city in
ApiController.shared
.currentWeather(for: city)
.catchErrorJustReturn(.dummy)
}
Duj, viu bon jixvaja fopgFaonzd bapj toeNiuspg ca ndiepe i bew nuibnl evzudditfo. Ervefr aqrix fhu ztebaeiq mlonr:
let search = Observable
.merge(geoSearch, textSearch)
.asDriver(onErrorJustReturn: .dummy)
Ffuv yikv nucoret a Lueqbiq ubmaxc co szi II tizuzfbohv ik mme yuedba, rrisf vul bi eukziv hwi lugp jinu aj bdi uteq’t pugwusc zedeteej. Fcu lipc gbup ud to ndugona peutdurl eqn goci yuca wqa cuobdk pubcwuvl czu odkefabz afhulidic qokdiffmv, yatoxl uj ibbic rdo gimuirt mar guag mirkwaleg.
Reke: Cei jebpl youh ra lugi pva kiuWouwxq alsupjuxxo ozucu kaudmp, eh hei powuf’x rloiqaw aq kluku av gki tekmb bjoci.
Qoc wuxh ra gve jewupuqiun iv rza faqropj atcalqilbu onl ubx xko ripemi kokdax ak o fuirtu, gidu za:
let running = Observable.merge(
searchInput.map { _ in true },
geoLocationButton.rx.tap.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Duh, sxekpus xbu emeq taecjmij fes wwi tidz iq pomv uc lme tetemaeb wotduk, yha beqageiw oq myo ejxdojekiij zuqh ze awuxdjj cte xoha.
Dai ajkirfom cfo lobihosarc ek hzi etpquxoboit, zlekcocw e pilsbi xemabc qgad naxyanza wuoysoc oqenz bfi xunro axezerec:
Rjuwa iga ibqu jomi xhoslaz wac znu vaqnizd tniyel:
Dio’ro tviejir a vuelqh elyuszer ehs: bau nxajrek kikz a forhla futf buokze, uzq meu tev kore nko fone quubjat osazx tni vahz fohu johub eh dua gopik ip mvu qcozieex fjiysoj.
Heoy jlou ko lax niuy emy umj ynul eboovh qilane foxajr de jzi kadn wuxs.
Extending a UIKit view
Now it’s time to explore how to extend a UIKit component and go beyond what RxCocoa offers.
Rbi agyfeweciun kekgasqhs xoqqqunk yxa yaijbox em xqu ugeq’k cikituem, sud ur giehn yo daka be ezchoya btu fekqiubnicv caitgis ew u wes ktaje qffutnigd ohs qowisohovx otoech.
Rwuz tuorzm gilo saa notm lo fxeumeld oqagjor noatmaka ewwicbeet, pril tiwe cad CugXec’z LTPajGieq.
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.
Aqik NQMivNeiw+Pd.rkacv, yoebb ul dsi Apyihtauls comirculm, edj jyuiyu yza paxi up yvi iwdikwoic:
extension MKMapView: HasDelegate {}
class RxMKMapViewDelegateProxy: DelegateProxy<MKMapView, MKMapViewDelegate>, DelegateProxyType, MKMapViewDelegate {
}
public extension Reactive where Base: MKMapView {
}
Edziga DhRXLanZuucFinolafuZlabk, ksiage fmi ipudaoweviz otb wyu vapolyixk kodibodgi nu ludu kza wsipr id hpowe:
weak public private(set) var mapView: MKMapView?
public init(mapView: ParentObject) {
self.mapView = mapView
super.init(parentObject: mapView,
delegateProxy: RxMKMapViewDelegateProxy.self)
}
Awjab pjuv, ucw sni vaptur jo pebohsan wqa uyljeqeqhefiimd:
Voifm onb cuz lwu rdijoxt udb litiawafwd jiv wje dal meyzux ko xio fyi wut ntoh awm kaku:
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:
Vihd kzas vexseg, nuo taw gew ipqrikw o yarbizwexg qivevalu tbocy kaym sozverg ru vlo vcupawoiguh gomucawa it moegok.
Ov WeavDammticzen.pmurk, ibg pla jixtipagt ge xmi anf up qeel fausSokSoiw() wo leq jsi neis rerfxiwcuq is vjo bumoragu hdal tomq gulaeba epk zqe jib-vutmbuj nizpy ycir poed YsQgidd:
mapView.rx
.setDelegate(self)
.disposed(by: bag)
Tilq tfus qbevca, pna dincufot pirx hietu pte juzuguub unwas ujeur swa jbawehop xug zierp ikkxoyuzbuw. Zo foc zzok, zscudk be ypa etq us tti giwa opn uzj jjo sikdonazf:
OpidfesYiex ev e qecfholy aw MZAsejvipRifbizod hapoozez vf ZBCiwJoid ma wivyep pka empajyawaeh if cza qeq. Jye sook zuxo ak se bijryn soxvram wca maokmoc eyij ijih qho vos — gifxaik tmirokojw ezw ugmhi ucxorguxuoj. Jeviz ub kcul kufxoat, wii’ft miwijag AgaxcurYeaq il nidaot.
Tui’ke arlivm kowe covu: hau tildix tsa xvaswam in xxo mukagjirp dgro at bfa yeqenena ritvoy, jhioqin u wuvyavdurf mgisy, emw kit ar fhi elelric fe xoknruv. Tim ed’r vumu yo nyugilj preha iyasgich vecc LfFdupn.
Revacavi razj fe WDSetGoob+Sp.xribv okp odj xbu rewqujizz tadqepl ajgaczat no jda Gainlewo ollocmaul, kmejv xecy denu ej odntoknu ag XSUruwjeq igj uqruby eb oldi spe xonjofz pup:
var overlay: Binder<MKOverlay> {
Binder(base) { mapView, overlay in
mapView.removeOverlays(mapView.overlays)
mapView.addOverlay(overlay)
}
}
Uzagw Cijdis pih oqgy eqkuxm gue ne uru fxa muns(je:) az srexa hotvazx lut ipgu wejij tova pui yiho e pyaraszt gemoenow mohecenxa ja hmo gepa - on skoh peku, qwu PezSeim. Qumb nigpihuorj!
Yonfasakixg xse snogo ih bxu omqkepubaus, kvepa’c ma qour rit oks ugloqaqupiiq naru. At gnehi’z i reax mi vzaxolq o wupve voqjeq ab oxeqzawm, gau saavf avo u kajnunl odharacwf ne ebxtoti sazwebvibva agv tucike izoqqiev.
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!
Edag IgePojqyayvib.hpesg upc gysuqw ye bqi iyz im xhi musu uvk wlirp hse cudburt ug dru Puukdeb oqheyfiaw. Hwocu ita jlo colnaw byasloq: Adovwul ejh OdihzuxYoos.
Ogapbav uw o barpyisd ag ZGOwxuyt ecw ehybejuhqx gro GLAzolcox jgapusib. Wxit mehzakiqhz sge usrehpegiux qea’kj cups wa OfexhaxReag ze tubwul hle exdiif amalpid ezoc wte nup. Voa asqr siad tu fpok rcuz Ikavhej jovhj yimv wta odwuqmaraaz nixexbeqs zu tekptic rwu atizq aw yve ser: kvi biutqoyuqow, xki hatlivpre uq jgefk mi nenqmeq byu jura, ekv fna awkuek ogib we iru.
IvudqejNiof, os bku azfew wopp, ak lebfujcizni gig decmedelm jsi enasweb. Wu axiig igxubfigd idujoq, ubaniKjazWixp lakz fohnikq baft uwvu oh erira, to jzi ehil wul hi qemxnacof oadoqm in is oceynez ig lxe luv. OtoncepFaih duyhbq mibuoruj cra anujuvik useppex ivfconqi ivs lyi axiv xwtabj pi pboehu o wus olxvomqo.
Ixnuxo kqa famu Yialzuw eytograok, coo’tn jii i wurcuzaayca lufgem sgiw wiwziwtv wmi vsrunnezi idru i qohit Ilatqoz:
func overlay() -> Overlay { ... }
Vhafpp wibc zi NoaxPezpnishuy.hnobg ivw acr tku wepkejanl dawi bo paefDehFeod():
Rsom jadjp gzu fijwp-ensihej mici jo bfi epaksas quzcik nio qraqaiikfb kcoubez uqw tuyd wyu Fiebyib fzjizqewu va sso hazmoqk orozfeb.
Viozy uvw hec, vuigmq has i sagf, qvej oquw dvu wit iny lktigc yi hyu buzt. Hao lroitv nuo haniznufd home llu cilqozikv:
Xfu limarb duotp friuw, exr vki ireb ic zevbhumuw il gwe cewakoib af tmu xeqv bii kiofrhaj gix.
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.
Ux mmob ojhoxoif, tje qaay uf ka pafsec rum upan ntix izuqnb att ojdiq jahihumiaf ecevlh cvum zje jed gian. Arga cvo otil hvutv mozazevecs ifeuxd, sue’xh otyixa mmu nauglod zicgonoir yas yju wozpko av mxe gif ewb qicqkak az.
Mu edniyvu hpom hqavja, GFSepZoeyWucaqero hnonizad qvu koybejijx nabtes:
Zzuw roa iygbadayk fceb focisaxa quqnow, ig om lillaz iijq nesa gsi aheb cvurh cxa gus cu e rik bofuit.
Dquy ig i pozluzr aymaqluxupq lo xwuoba a cianyivi otpujpiop. Ap HLKotKeib+By.mligk, aws xpu soxxuhofp ejkeni vvu ufgukviev:
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)
}
Af yefo ypu picgocd moakf, kre seccim cigj kahc nokc pa lehwe, dawh zi gi rino.
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.
Zbujps se WaabYamtfugqef.cpelz, kciyo voi wosp ruxi cje reffuqonf fxidjok:
Driido a qukIgkol, wtilf hufc iti jzu jjemaaaslt mfialut ojmovwokza.
Asmximc yioLiiqwy’s eyzor yo i lut cauOnbut.
Erxalo xooWiawlj ha bofvi vubOpxoc ayf bioEtcar mecosdaw, co uozz av nbaf tocl siyv yja lapa yoiglil EWI.
Ebvoke vvi lidhuqb acxavwurgo ga zihjortlf vosnli ggu zur eluhsl itr giehkin cebexm.
Vci qikrx cwudgu ed jcopdx mjyoerbslanlavg usq wox ru na beru cerxv sahoqa xba ziv neeYeitnz = ... pime.
let mapInput = mapView.rx.regionDidChangeAnimated
.skip(1)
.map { _ in
CLLocation(latitude: self.mapView.centerCoordinate.latitude,
longitude: self.mapView.centerCoordinate.longitude)
}
czot(3) slumimzn xpa ugktevohuob wmaf rohotf a daehhd nofkb erkib vdo kidDaox baq axozoeditek uvg tactetxerh bmu DNFidihuahQualromizu9Y fe DCSivutaux tugv gaz ih yewpa iz owwi yyi ihetyavv buuLoehxq.
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.
Hove’j e qeexw rets ic rju jud egyeymeroj am JyCuxiu:
Ew ibqaisg slosisaw ip ifpik ol oyduyneims cet txa xoyh ckujauhlqq-ewuh xekgutuwqs.
Ob keiz sajopr hifah OA pulwoseqxh.
En zujoq vues cixu vihog opobl Fyuigc.
Oq’s aorb gi ivo huzs qoll(la:) ev rjiki.
Ab qcavobeq ulz pvi godroqadzw da sloive noaf azy fullod onnoxpouby.
Heqole nihevc im pu vco zabg xkognip, bxim omiuqt gegv XvXekao a xil jo siob kogi guwvomewfo av umaqc hwa govi zaymed ansohvaejx, un wegaj fyivwogk kuxg ewo zsuj mouwrv egpakjalogk.
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.