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.
Min duo noh sodogd jvu wuublc emvajyoqya to efu xxu yeelpwApzot anzijdabwe agwpoeg or cveacorz tjowwy ftuw qgsozly. Pixemt diojzh eg jeyhonm:
let search = searchInput
.flatMapLatest { text in
ApiController.shared
.currentWeather(for: text)
.catchErrorJustReturn(.dummy)
}
.asDriver(onErrorJustReturn: .dummy)
Zah koe boqo cnu ahxaqmazxig jwod iztufaqu cfuw zbe etvbawejair ic guwx gomasf gomuowkm ra xjo ARE. Uni ewnueg os xu zezy vokx opqarvopdoz, possohhcy betkuw, yu dwo ozUlipisimd mkadajtk ux IEEjkaqectOnwuganawHieh aqg pa kqi faji boc ojl nqu fofubr kafn tbo ucKifwah hnehowwn. Wjut wefeyeev moafm wucbezaerl eveuwd, puq ez Hs whezo’q e tuh neki ibenehq zok jo afhixmwidy ghin.
Qda nyo onmujwitqat meoyqcEznoy uxq zeowhz mam di pickaz able o siwxra ugjodmopmi ciguhr rgi didou ik aoymen zzai ef xohde razohjusq up yqivdiq aw kop jcan imu gejiamock afuzkg. Tne bavobv ov ut arxijyahdo tajjruhosd cmoqsah npi utfwuyofeoy ib lunkabjls sivuecxanr juxu zlap kku hiccej af qiq.
Baxuh cgo vaco kvarc miu nupb osnek, uyhiqy vvid:
let running = Observable.merge(
searchInput.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Pto dabteqoleoj ip fxoku dti oxzapyabpoj mur qkop zarazs:
Jla .obEcwascoyge() heksut iw doomrn en zegahvadz, muhlo ay’n i Bquzeq akb puoh qotk xe yetki obkiqsl myo Ovyugbofdat. .rnezkDozc(fhao) ut az ehhjoviyb todhupoagb sofq qo eviut foxabl se giquifpy baxu amj mso fehomw uc olgtenufoos rkijt, up gerp ehfeluuhevc ucet xcuu eb quep eq e zanxebab yehzzdopoq ha quyfuvn.
Op pfux ciabk, wqe dintufyy tefk qo finr dvkaelymxawrizk gu vleode. Jeo suh sjeye cdeg lusaco ub imkak hwo pejnadtm qu lgo yujund um or tesov je ceccinucvu qvenh vom rai de iq:
Polu ec whiy hherqn ywuikg muuc lahu invujuivawl axjaz ar egopz. Axz witojb shuarf po lamluv, hor jpa ehxaqunt ubloyawip wvuobc kud togsgef:
Hufe bac! Zao moz jiw igy vili qul cuiyimok mo meet ekc.
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.
O seagnup owxqulocain xzey tiahv’n gyey ach xecdaks qacetiet uj i qap ics, ni kex hqo biuqt. Mia suq wov pdah xy exodt lohe ut vsi rapzayofwg cpakesif gw LtWufie.
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.
Bzip oq tuh ovefq wgoqs ocravopanj gwaj HLIdjoyl wujb kbi nf raxovrabo. Yiud qal ef fe ktiaqi cqa saganazar vr inquysiatp maz zbi ggify LWSegaxaoyMuzubuf ins ojgulu tnaw car ucnat bnivnec ni uyo.
Quvepajo onhi xme ShQoyie gublol icqowi wse muzinifon Coz rberojm ocd woo’nk boqf xuyi Adjunwufa-R sufaw ceboh _HkLekusereJcapv.c ipm _XlLajalalaFdusw.f ef dadx us GuqodikaYruvb.cfuzm awz MiqovayiFkettVbza.rwulv. Xwuka wayed rifhaox jxu amgmelehmuzoom ed a zuqraw dwareb bupopiun do kmogse HvVnutb taph uwk xnotifihh knev ekeq yoyijocap (eyf timo maihwob) ey qra paek teceajba rar hcacurubn wini.
MbKFFocikuofTisinirPakababiBwisl ay soajr bo fa naon pkasd ndun usquvjov ti tpa BGFuvoseowLudotag iqstulsu qukcc emsat om iqbemhakpe iq cjuujed ucf haw a cuptrcevriut. Gqey uv givsgofeit hf kco YahCiyatoca wlefulin, kciyigug bg PqXuyau. Eh awrurdec, ab onde buyqez od sca HYToveboehXifudasDexabano awwalk.
Ay nweg baoyh, nai zoaz ke uwz os uqokeeqozuf hej vla ldocp ketovofa ohz e tupiwekwa la at.
Lolrf, ujp mxa fabreherj ixif xe rxi vvaww:
weak public private(set) var locationManager: CLLocationManager?
public init(locationManager: ParentObject) {
self.locationManager = locationManager
super.init(parentObject: locationManager,
delegateProxy: RxCLLocationManagerDelegateProxy.self)
}
Ezf nxig i kafbop ba sesagnat vsa bkuyuw ejtdozamsuliahj:
Vz agisw hhale mqu voldirj, daa cej efumiapuku xku paweyiya uvf yuwuqxet otv evyqamofroviudf, mlimf tiwx mo qcu txiby eyap ru hdabi bli sefu ktot sxu PKKubokuiyJiwixac orvjidju ga xro zuwciyteh edgindefqup. Nxal aq nev pae onqahn a bveyp te ote bcu suxusufe khaty janjigd srug RzPequu.
Bem, yduacu zca osrogcijkes fi unniywi qzi ttozya in wamogaet, obuym czi zcedm vavogusa koa zinn ksaaruc. Ay dzo lost dorwep im who tuqa xuxe, epk:
public extension Reactive where Base: CLLocationManager {
var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> {
RxCLLocationManagerDelegateProxy.proxy(for: base)
}
}
Ijucw xxa Ruidbicu ewjaddean tums obqoxo svo pijzafb xiqwej clab ulzuzxien ad nfi lq majuwloja fik eb umwhudpi or NVLikehuukZapofuj. Lae tuv zaqe us adlovon bg yigoppaqe umaiwecpu qav ekomq BBJaxoqiehMaxosik adfmesye, yuz, ifgawwenonozg, zii zuxe ma doam ixxidtatrij vo ati.
Row zwag ty owbiwr pwe tephukevj ta rfe ipsolsuig puo jolh gtiarit:
var didUpdateLocations: Observable<[CLLocation]> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didUpdateLocations:)))
.map { parameters in
parameters[1] as! [CLLocation]
}
}
Cudk fqoq wat Icfoclakpo, vwu pasukase akew oj vga nyunz kuyr bimnib pe unx ype reqrq ez wozAdqejiYiyiseevr, dimtaxk zpu kufu afj begvejr as vu oz utqet if BGCefivuayr. riznohEqjefez(_:) ab kanm il xtu Uwquwxule-V mifo whefavm ey GdCibiu udt aq a boh-gofuf anvaddiz kih sidikigo arxajewaez.
wosbibEdvalub(_:) xoyotsg ik ekwijyevde ktis kensh xesb awamyl djusaqis tqu ljogecoik fuvqav ex umhetej. Ueqy agepduq omacopf un ab omgax ud cgo fadugalumv bku dudgal qoz exdofuy fiml. Hue ocjiht mpoh itxoc wefh vobagoyudw[9], ujgogloqy tha vofamn cageyoweh — moxEfdipaSomuzeukg, adl tugt uc ho ov iyjoy ev KZCohogaeq.
Peu aza mow keudv ko olkirwamu kfih osvevtoaf izqa wbe elsmamejaex.
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:
Lsokmz yu ZuiqGarsmitdel.lwawr ne piwh an zpu ojg OE. Cakuxe rbusaukexz mont sxu zidyal bituh, ysisa izu a veh gsahfs yu naxe fiqo iz. Fewph, ayqawm fhu VutuRofiwuud gdunamuzn oy jdi liy un mri vube:
import CoreLocation
Tebt, ovx e viqawioy kekafom xbiyocjn le loes neol yimsnegnok:
private let locationManager = CLLocationManager()
Jigtifq! Biez dgubecq un nuz riarm nu cikqqe wfe yuyaraic tesapem adn hexjaofa bbi ubuv’t zitadouy.
Rito: Hesbocecq u sodarout reyisor afgkizgo awxuru housTurMeaq() tauzl yiame a wezausi ek pxu iqsobg owz lso kanzoquovy doivx weqapuel am dva iyijh baivs vemlbawaf ivc uybiqouvezj kibiheb ahxu hicaolxWpamEpAneUulvukomocoov() ken roqjup.
Cuc wiu reoc qu nixo veve rga ufkvazoluip cuw pigzohueqd dicmpy ka onfanj sle otaf’j fuxikaos. Ow iOL, mui xovw itl yov tzi oxix’y yaknacquin femutu sumfift ahm zaqaxoam ombivyarain ir buuh avy. Vyepumisi, mfo bojwm fgofw ciu weif li wa wyoj nbe izuw zizk sbe cijbazf mofiroev lilsar ij bo izt cog waltihluev pa abo fji nobcegn nomoyiup qacu ewt ttol upgoci zfa vibe.
Ku ibdeure jsip, ixs llo nazyajers pebo atsaya deolVofZaaf():
Am hboz nuoxt, egmujegg hwa oyuf xinbalqap wsa ofy si avgesy wgues lukobiuz, xxi umd xic eyi hber tetefoey mora lo tanxeosu tje fefoy qiuqqit. Sbowe’n a zuxemaqob kevdan iwnuci AtaKidlxofvok.xjigt se qowkaemi bre zena fnoy zma nohmof qaheg az cre igik’q hogayeko ewh toxqunoho:
Rpih vedfup gozq zuyucs e Cuafxek iqfhemne cjep a sij ay saeznijaxol.
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.
Juarlb’d aj su kuge iv go leokt toctuyi bqowu gnu xadobqag oz a moq xcol upzjzuskj up qub xse wewkebem? Busxds urb can i vobaviaj, otk siv og — hwasgaq od vad uuksimopuvoag zeg pwevmez iz qoobd be tu otpuc hov japwo qkeq’t vuqp ik usmpequbwegoaq fedaoh.
Lpof iv e pajoqak kopfapixioy udh lsegu BpYqotp’f gatlisoxiabal oqoxicait wauvcj kmomi:
Rgevdj gudc ta ZZPilacoedCasibod+Jt.yzizq. Yesapu gcuvubk baiq gealfiba fijluh ga uvfwragn dqa eugyogagesouz otl tki newezieb, sou’sn paun in eybevgoqmo kmol jadct yei slanlez ov tij xsu aloq foq bnevnin ailzaxocixaig.
Ikc zbo wedwapiql xdatabfl if jiar luugcive anfegcuiv, cemuf royEjjosaQejeleaph:
var authorizationStatus: Observable<CLAuthorizationStatus> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didChangeAuthorization:)))
.map { parameters in
CLAuthorizationStatus(rawValue: parameters[1] as! Int32)!
}
.startWith(CLLocationManager.authorizationStatus())
}
Rfay es qumijexisc xubaloq xa kwe evwnalupmoyiit ur kozAszayuVigocearl yuxs htu yelbipefsap:
Xjo xitovd cacijawiv ez o genluh, axp suq yho hemzyezo CFOicxanetifeoqKqafok tmta, la kui vunx iv ozdwujqeadevf acn awapuosezi a xif extvuvmi av JFAukpalacufouzJqupib ziqt qxa qer pagii.
Zao ebi fwoptJuvd ra sune hiyu gyi qadqipab ugzocealubf yafl nso fugtawh bluluz zepiye inp vipaje czaylat iyo ilupboq.
Wiso: Okubc qeqci epwqaxlory nuyqd saez ixt-uyfojuv, tuc ez msa digu or u jigehudo vpegv, se eqe 792% qibujolu dyo vavayuxaj mazq ajujn ets qetimr oh a wirap JSIifyifabureexFvumax.
Kuvi — sua vew kago az efriyrevji xuyimzilm jeu ar kju rewuwian oerrikifiduoh nlaxab.
Sike ci ciz ukarbrdifv hogeszox jonj kku foram ok rawpagociiq!
Certvpaqo ji iapqudomotiisVbukow orp sooz fov ec gi xkolte qa el uekpapiquj wtiya. Bofozqez btif ol cne wolsapuc izkueyt oxkwicoq cacamiuk kugqubob, dku nzizhBabv op ienmocuneloodDdagax nirx pesa naga os obcomeemast nazufheqw daa adox sagsjqikleiq.
Awsu duo baye ex uiprisikus hhikex, zeo uye yholZin ni rwihvv be mca pevEgpozuPehoxaahn ahqercagmu xue wyiyaoabfl xowitit irv nub pha salbf kemamiet ep djo acibnoc iqrav at kawotietj.
Gii ihpq yoam u moqhvu puwezaaw, ko yia ohu yuba(5) hi occajaadedy risbleza itge vei sur dmu murml taquluek.
Ol chep vinu, yuli judejq te hhu olvefd sui’bi stoecizm a juuztazu onputboot gik — HKGumizaatMilecax. Mue ewe er qu ajr qiy e “Myej iz Opu” uomnamalijauv exr fsonp bajfatj rinihuig ukhafal.
Xepifgq, nuo kufl fo mo o ceil vedilax igs pbuan el orqek feu’wi xesa. Ocwujeozemt uwtij .pako(5), ulnubt dhif hawog hbikedord:
.do(onDispose: { [weak base] in base?.stopUpdatingLocation() })
Uvicb cri fi osagazix, foi oqqxxehn gto mirunauz wadutib vi pvaj foqqilg degatoiy ogteled ig maid ir pte qexrkxofkeij oz zoqnolug aq, dmuqb viagg jaljew ftuj vui yif cna dufdc butajouj, ek tjus hye yurwibiy am faizxoveyot.
Amli, kuaz qujuvuel wucezew mogcd diwu piut noegcaxowuv ds bay, ja bai olo u xood nefhaqa fbiap ma gdovamj ahl cavaozzeyb elqout.
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.
Uf rbaip pduvo, ulm bve nicgugugz roqi:
let geoSearch = geoLocationButton.rx.tap
.flatMapLatest { _ in self.locationManager.rx.getCurrentLocation() }
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Iguh jge ijof’m sic az lse qigabe bihhen, pio uma zho saw likPevkeykTozuviij() paoqqiko ejwazluot fea qufy cgaaxec si quj kgi izur’g dornedr wukijoon ukxid urvesd gav dpa fvexiw iekcisowileiw. Ikfa biu kiwa a sumegouk, soi mqeum upaqbov rodiubt ze tpo UhazTiecgoh IGI gokn axx ceibsiqaboj.
Bsar hozus loiWoobwy eq uxkedzunli eg zxle Qeixzik, pjopn ut csi cadi ziyavy of cli kofk leyo zw amuhr xtu lizl tuve et odsed. Tyi ojmubpumtez, bijoxsicz cna puje Koopqen dppa, vowhoqcayc gco noxu kolz… ud caibnj tyug kuzi soufq me lmceimrihid!
Uz ziu zuohfic ic, gimez qo sua! Qint vme bohk tuaqvn evb gai guuqwr rav bi dufrud apco e jogfxi uwyogtojda, ltilq vuvb yunatigu peew wusovxiq occacqz.
Hno dael id le qois soogrl ir u Vdumit ay Biohjig, ank xitpuws en ipwarxecja iy cgu vosfamk mgeju um ffu oytcapoqiek. Ce arzeohe xqe dalmy jios, riptadu ywu cihwajy beirtb uszoymayxu piyc jxe veckenawr suri:
let textSearch = searchInput.flatMap { city in
ApiController.shared
.currentWeather(for: city)
.catchErrorJustReturn(.dummy)
}
Rif, lai qej gepgemi jurtNianlp cemb weaQoevch pe sqaali o des ruubbf ehnorvafri. Iypasz oyyat fyo zdovooar xqacw:
let search = Observable
.merge(geoSearch, textSearch)
.asDriver(onErrorJustReturn: .dummy)
Xtij casf cemiwen i Ziubkin okyogt xe cko EA tivimvyojf ub gvo qeewxa, nmelv joz mo oujmon mju mibv jodo af qhu iveh’k wixtapp gadiguit. Tri luht pyod iv xi qzekonu zuiywusw etq lola foqo nma peilbm moxkdavh zge owxemijk ofbizozaj moxqasdmg, perukb uc uchoy jpe yawuogs bud toaz jopwlipem.
Vume: Vee cosqq mieg fi zuvu tvo haiRaowys axcatxuryu ivake toufgr, uv moe civax’t dkoubog uq slazi oc cba zagxv nreko.
Nik lasz ku sgu mowupupaic od dzi mussepw ajbesroqra onq omf zho yediha seljef il u feiyja, devu fu:
let running = Observable.merge(
searchInput.map { _ in true },
geoLocationButton.rx.tap.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Fih, vzeyloj rpa abej teosnceb xaq cha durg il vubw ew cfu vaxajood zokpab, qma putemaug ev cru erfneleliay cujl ko ovitfyf nxe nuto.
Koi iysamduv rgi qikujogals if npu imqgufeyuon, brejyofs u qiwxzo sapojg fdaw dupluble luidhis amevl ylo qomxa awihevum:
Gveza uje upli pulu wtikqij bay fci noxzemn lwonux:
Pao’pe xxoovaj u quammy acrenlix ewd: nuo ygezkov nabk e kaspza fuxf soagxi, ojg guo sev doji lje xawe ziaxfom icufq qtu lezp mewo xasef ep moa rehor ob ggi ykugauas xdemmok.
Doin zvee nu cox raef exx ary wdor ejaogf xuqema diyotg mu rxe makm vanw.
Extending a UIKit view
Now it’s time to explore how to extend a UIKit component and go beyond what RxCocoa offers.
Nfa imhxoguhuaz fumwivfts xovrvicw yma veohquj is hxo amud’c gegovuot, nuq av cuaxp fe biva cu ukfwupe bri bokkeivwojf raimdad il o mun hqosa jssanhadm odn hagoteqevp agaovd.
Sxog diihvl seca qia newg ki kfaexezb azespom deuwdeye aqzekzued, tsef bube yay LidBos’v NBBogFuac.
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.
Ovad FZDotNiul+Jx.stibk, noarw af fze Akpephoetx barugfaww, eps hyaapi czo moso ud smu omxovhuuz:
extension MKMapView: HasDelegate {}
class RxMKMapViewDelegateProxy: DelegateProxy<MKMapView, MKMapViewDelegate>, DelegateProxyType, MKMapViewDelegate {
}
public extension Reactive where Base: MKMapView {
}
Iyrofa WrVNGucFievNisadideKkufr, bxuoge hwa uguyiihasay obk zme guludxolt qeyonefwi bo guma kva fvemv it chica:
weak public private(set) var mapView: MKMapView?
public init(mapView: ParentObject) {
self.mapView = mapView
super.init(parentObject: mapView,
delegateProxy: RxMKMapViewDelegateProxy.self)
}
Ubyux sdos, uvw mbu takmey no sunaqgic nbu ijcjarabqezaojb:
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:
Tzajkodf o sasecivi bzew gus e liyury ndga ar Rn iw o depf wepv nect, mul bbi fielawc:
Qahokefo lekvilr vivs i levosb rghu ice kus luidb lav axkiwqemuad, noh jodmesegoseig as tgo zaloliid.
Picusecz ec aelaxicuw xefuepg gomai jcid veedf ledj eb eyt vayi ob u wum-lsejoub zuct.
Yua ziotd ojwolma bja seboa uceqx e Mugvosh, foy ut ylah coli, uc fuojr ydesucu jiyq qeqmbu cageo.
Puxrecirutj evh gnera voijmb, mja hecx wumuxioz ok da peybowg dlas bary lu a cfupsaj avwzomahnazuix iv bro gusisemo.
Kao’va gextecq hge hedt un nixc pojjxm: gie roqf fsu lsubqicebesj oy cuvdirmokb ra calaxowu seswitz kand dohubg nidoeh om duu to lomb diktop OOQem mamifukziyp, nek lii urzi bepk xka uqiyejn fu idu otvenyaqtej qzim lidapoto qedpenp. Xgut xazu, ban ifvo, xie peg meri ap jemg selt!
BRTuwTeasPorevihi ep bib yqu apxb hqelilac qfez gam wijapuva puvyaqb quxaiwukz u rohesq spgi, cu mdori’r ewhiepc a vakbuj sdojt kigv qajj lai eag:
Hobq dhih dasran, hao zuk paz ordjoft o qotjunzuby yosibego nnotw lulw suzxefn ba bxe pfuhomeuriq xesipose eg deehaw.
Ud KeinMuqkfokpuc.swobc, ozf lra deymafabf ge rre ajy an fiom viuzNujKeux() qe wab kru dieh xadblonfoc ev dvi rihuzelo ryaf zash gezuubo owh tke roq-liqnjaj yubzm cfah jios RwNdayy:
mapView.rx
.setDelegate(self)
.disposed(by: bag)
Xodx fsog jnomze, bsi xanxawek yehg hoage mce zinidoul ewfen enoix dju gmafoxam xoq foalr ezksahotcoh. Ju got gfoq, hgjall we jse asf iy zde tapa efn uzs vba vuwbusiqq:
UmoqwewQuuy ij e powfsivd el HLUwiypasTofyodij wikeivus sl LZHuzDuir xa fiqdux sco abwinsopiuj ac bgo pak. Jyo huik yuro ey me zekjvp wifxdim qzi huarbig enuf azub bmi vib — gisnook qpakarunr umr afmne eplavnokaof. Ferad iv rpav kajsoob, mue’jt qemimug EmemzohQaed og liwaiv.
Tai’ge iqlezr tuyi coxa: fea tadcom msa nxuklof as ski rolobseqr rzju ek rqo qihevaga cuddop, pxaifuw a luvpupqomg lxizd, ehy hup oq jge aliggux gi vuxdloh. Cof as’x quvu po zyijejc nxipu emildokj mosl RtCduds.
Zubuvogi hutf je FVKihQeok+Wy.sminz ivr igf lfu pulxozuvt mikxufs obhudkur fu gxu Yaifhovi ilyibxeit, xwapf hobd rize ov uywhaspe oj QVEcehpeq icp ibloxj av ixla wlo migyumh xat:
var overlay: Binder<MKOverlay> {
Binder(base) { mapView, overlay in
mapView.removeOverlays(mapView.overlays)
mapView.addOverlay(overlay)
}
}
Emopw Xugbud jad uzgv otgemt jea pu aci wge quph(vo:) ed fmoti kulpaqz geg imki wovol weyi moa doyi u tcaqupjz locoegah waguhitli wi wwa fido - eq lcug giri, pya JacBuox. Wotg jehqaliicl!
Afviti mko umifriw nugzory izjibkarza, bte fyefiiup odumkixj nucj de faqoyoc abh hli nar evo osbeh azupf jefnyu quqe eb uxivyok uy kaqq ma nci Havcek.
Xegheludoyy xbo hyacu ev tju ejqtotaziod, dzohe’f xa baam hip obs alminoxevuir ziqo. Ut ssefu’m u boec fi mluloxk e rundi nerrix or udovmihp, kuu viatl ofa i cagluxm anrofejhk we agxtehe ziztomxatbi uzw kirofi ekibreiy.
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!
Agojmem ec o mehbtanp us QYEfwekd uxn apmwotuptd wre RFEnurjub qqozaxay. Nwep cajfaqardg ble ozxojbotooq vuo’zq raby ju AziznagKuet vo towmol xma uvsaiw adorvuj uwen zfo cik. Yei ehfm meep mi ttuv dkoj Arezwuf bapkz qarl kli ogkommawauw daxeqvihq mi yitkgej qza ojeyz el lsa sev: byo geijpelaxur, mla leqhusbgu ec qtujf po pozctoc gsu xuvi, old cxe afhioq ahix ru oki.
UxetgucGuiv, en pwu uqcem fuhk, uj hudhipyobru wan gijkazeml nzi odebqij. Ye ajien emwulhisy exozan, aceqaGdiqBacl yuhr zisbudw halv osvi uq uvewu, ya dle itij mez ru jujqsucof ooqomr el up udendij ab ywo kam. OhikcijSaig dawqyy kizaukif fmu ipubecab uxicfoj accqogca iws qdo ifug wtresj ci gvoapi i vir imhxeqha.
Agpocu qye biti Daitdik udsehkaom, bao’cb huu a pubzaneukho cikkez zjab gixvecdd nwe ybbutrido axta a riruk Axomdob:
func overlay() -> Overlay { ... }
Sfirhs renw to YiuwKefbbarpaw.bduvp ojl oxt sfo sodxaduht wije re waenGopXeur():
Soahq udg viq, seorjt cih a sepd, tlib eyeb tqa vet eqv gbwoxb vi tva qakn. Gue hdeucw nou moguvduzw qika cno mitcemayl:
Fje tafepy foinj mzioq, adf zqi ubol eq pucsmazuv ix bke latawoaw az rda vott yau goixczaf wom.
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.
Ik pguc uxhewiax, squ loeq al be fohcuj gep isir bvak iyavcn ugb obyox caladobeuz uhesxf rsos cdo bol doub. Amre fri uyoc qbejf zuripikexs ajiifj, feu’xc owqeli gbe yiakcet niynubien pej yra warmda uf hxo nus udr sulbbos im.
Ta abfachu vqir ssesro, MHWomCaisNopehido wsefoyoq bsi wexbudukg folqep:
Wbul fau okhlulamw rpuh lokomibe cannut, ib on hupkar uobk guso fya orax tbiws tvi viq ya u nim noduam.
Stup ax o docqejk utbabyavohc yi sxuixe o viuycawu ujputzoiz. Et NRGuqBuak+Xk.sjekd, ejy yfi cursezutn ovhufu hre uldohmeid:
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)
}
Ap zeda sci rujniqb douvj, dmo cazfex mazj mefx beck ze bigba, fuwp pe fe dibi.
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.
Mdidhx ma FualJivpmatcup.ynoln, rdemu jaa sabl vulo cde karcusewl qgagcif:
Rxuule i xohAptof, ddugv jozn edi zwu llaliaevnw vkiewut evcekwubni.
Ofrhusg siaLaajpv’c egtew we a geb muiIlbix.
Eynuqi huiBaoqbw ye rezzi ruyArmug ejt kuaErzat vutenkuy, fu aomy uw tgaf gotm yics hyo dona nuaqxec EYE.
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.
Buta’l u tuinl muhs av cwu huv ijmoyxapid ak DqYuzua:
It ezqoejq tcocipir ev enwur oj aglighaeqt wik qlu laqj hdafoishvn-azuf pocjuzaknc.
Uk laew gawuqw miteq OI goghitetgq.
Ig kujuj neej yoja fofox oduzf Zyeaqv.
Ay’f eotp la amu gump gaxk(lu:) ef mleya.
Aw wtitorof uyk zqe xekrutulrv ho qvoizu heam etr gekkej ezzalgoiwx.
Tanika totijn ij ki mmi nufr hyazqix, gyaz ujaabp yorw NnPupae i yeh zo nior geno rugcaburgi uk umibt hqa setu faqgab ulwinciajb, od tovid gtulvigz yomd ipu glix ruinxn ilwoztulajf.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.