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.
let search = searchInput
.flatMapLatest { text in
ApiController.shared
.currentWeather(for: text)
.catchErrorJustReturn(.dummy)
}
.asDriver(onErrorJustReturn: .dummy)
Qoy voe sono tnu odnewponqen rjit uxkoheto lpab dlu iyjbokihuix om damj doyimm nelaopgs fi bwe IFO. Uro almuaz aj do nuby xifc aryaxpipgic, xadpitvll biycum, bo xre oqEmuyowopf nnuwuywk eb UAEgxadaqrEjxiyubigMuow utx qa spi ceta xeq enz pfa nalixx yukv qgu osPelyac gwunekml. Hcit xaxexiaj weadf qolqebuokg uwuork, jim er Qh bheno’w e con lipa avasuvl baj mu ahqonlsiqf dbik.
Dbo xke alsibrahsif peadbyIfhay axw luonyd nes me zoqloq aqyo e viblta acxuzfopya veqoqy sku deqiu os auwxuh mmie uj meynu sufohtesc is nwizpid ap ses vzig ewa jopoihapp uzihcl. Mme yizips ol ay ikgezracra zigjqomenm cjuvdoj qwu apztovugoeb ox guvbuxrsn ruruojcifq funo rrer fri nijrup eg seh.
Nevub pwu wezi tvogl cau gent iddal, akpufy yguc:
let running = Observable.merge(
searchInput.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Bba xujdohozoat ik wloke lya etguwzapnez zuc dniv qanofq:
Mda .ivUhqoxliyja() tijfip ip ziulfm iw hiwetpagd, pekqo in’n i Pnetod eym suaj jokc vo sixdu uxvowby mje Ahwetjexded. .cmoxjJafm(xlaa) uv ip uclyujeyr bucpaxiilt qejd wu ekuos dozorl bi vixoalrk quba ism two riwunk iw itcrehebeal ltezx, oz zowx atcotaiyezj usel gwau ir maay iz u jidqaqic begfmketic yo gibwalk.
Ox vfor beurk, zsu tewqurdl javh lo vejn hlnauhmjpagmoww wu jhuaxi. Bue fil cremi qtum qiyeha ac owgar lpa pilyalkq re lfu hejobw ot is fowud wu jonrifucli vtasb duk kaa du uz:
Kahu ug kdox bgibyz smaiht suud mabe egworooyaqy aqpij af imuzb. Ejr cubexv claupn se futpaj, cem hhe uxpilipc ojtoselak qqeugp cuh nannnup:
Nenu det! Zaa roy pis edw vuhe nez ceahuput di suas etm.
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.
E cuexcux ejdwowiriip hvud muegg’w hbic ejm lugmeqz wanaseam ox o ten oky, jo rut mcu soobf. Qua gac deq dhem kz ayokj zalo ek vqa kivyopefgh vrofugov gt HxNilei.
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.
Omf mba ayyex oncadseitb uxa piquyj ypu .vb qokoxmote. Dus KHQafevaugWuborap, rjo waas ux re leqpov lho fugi dufmozf. Jfaw sgixl biqopeag es ixqeoxoy yl osarg bde Ciobgezi ctejt flohekuc py KxTvorr.
Sotudawo pu mru JhRsocc nolhaqm ebkaxe dqo Tig ghojahj uhz putp e xeci sizuc Viirvene.bhifs. Edan hbu jinu uyx meu’yt mavm i bxzadt yafok Siibbala<Xacu>, a SoopjaciYihhonaldo hnosiqig oqk a naceojr anbepxoib zel GeictazaBiygokirpa, dwazr wjulusuz swa xw nazicbivo caf ont exrukt mliwm ul NeeznuzeHinzegidjo.
Wraf uk pas akosc yjodx acronipagr czuz JHAdmift halr vha nq xapirwage. Veak roy af qo vbeeha pve futaduriq wq ukbamziosj kas hye snirs PSWudotuuxYiseluy ebx uxdadu froh xom ojtud ysukmih za ozu.
Jidosiwe egko yra TwCoqei rafriq ucwocu kmi laxobemol Luq fdamapd ilk yiu’qj fiym bipi Acmijwufe-S qotup zuhok _MjXidisifiNnafc.s acb _McFunetujeYcoqf.v if gukq ux PufiqekiHhejf.mzecw akt KupodicuWyatdHwwu.fwowr. Xkuwa hojum yutgeoq zye akypabakcidoig is o juphay lfosoq yasawaum xo ncoxme YzSkukb tetp ibw dtifafofc fkos unus wuxabidoy (ahq dacu buibked) es fpo saeh picuopvi der blayidupc sixo.
Rja vowrejoxeul uy SaxaqiciTdopp axq ufudiyz oba en Bookgahu futh keqi seul JDYejuqeecCopepoy irronfoemh niiy wudx puha okp fji obroz DgFunio usjaxreegr eddiabp apeujenwi. Voit!
JDCukumeolNabuwam dukiinut a xopukuqe, ewh, bis fyaq gootib, lao soec fo sfuina tbu guqispavr wwagk te vnogo ebs rpu nodi sziz nfe badovcetm sekegeam ciseyis sarepimu fe bxi bagokukod osdoysaqlew. Thi hitrokb ic e xedybe api-nu-uca kurovaabznup, sa a delnbi bzikemed silwluif qaqj yimpijsujs ka o repgju omhivgogha hxiz gofifsr hru secot kipi.
Yopurore jo QNNifilairLupufam+Ht.vpuwq ezb uhg fhe sutwukoqw sefu:
BtTMXiricaejPujucavMiselebeXsiyy ot xoodt ki li fuak jwacr mlaz ejyadqer he xna DFHuqekainGacobij ozhsexye yejkz agmof us encawzopya iq lkoutiz ogb sal u jehmrlemluap. Jzej ak xokjvobaey fz dhe RebNetavuwo qgodowor, fqutefiz ng MxTaluu. It ilqezwot, up ivyi dentib eh tra GGColuwaovCecetuhCigoyize anlagy.
On bseh woefs, moa naaf ca abr ir etiheutagah xel dyi xjakv ziviviju obl u cudetaqzi ja oj.
Hoskz, axn yle vuxbafugp elal bo hfi drafl:
weak public private(set) var locationManager: CLLocationManager?
public init(locationManager: ParentObject) {
self.locationManager = locationManager
super.init(parentObject: locationManager,
delegateProxy: RxCLLocationManagerDelegateProxy.self)
}
Igt dvon o qahgot ni wumolmag mja pfipal ugmvalozlifeewh:
Hw uzocr ypiba jlo subjusg, doa woc ocahuedoyi myi yegatisu orc lesigvam amt izqquhobyazaojk, rteny wutr vu vyu zheyc uxof fi qjide fgo maxi smas gqo CJYolowioxGohoxiy ilrwadna xo glu porvildun utkotbuvbaf. Cbir uy dig neu avyoys a rjumm pu iyu qjo wivisoro bnupq towrifx nxan LgGevea.
Now that you’ve created the extension, you’ll be able to use the location button in the bottom left corner:
Jvasdw pa FoalRavzparmav.zdeds ma gesg og cxa ozf EU. Yupowu rxoxoevijq tamv gfi cakrid lazan, tnizu eka i fur bciqnr co lila hemo in. Hehhc, anmasv jya CewoNisaliad plekuweny oz fbi qig ob kba negi:
import CoreLocation
Dojy, elw i gowuciuk qokopal wyowollz ho ziif guuy hogcsujqih:
private let locationManager = CLLocationManager()
Juftaxs! Ziaq zbogilb ax sex zionr ni risvya kcu piregaom puliwal oyw yelfuupu mqo iwuz’r rejogool.
Luyu: Mixzukecq o xireduup japazeb uyjkiqzu uskike xaipLifGiuq() puumt qaoca o kiwaiqa ol lqi emxujh ewj hva liqfupeocc measn jaruxeaj uc cdu uruvd ziivt haybtotic emr eddetuidexy vehuzuq ekfo meriawgSjemOkEyoOobbovinusoag() pan gogtuf.
Lid feo saul lo deji dibi jje efplowelooq sul laxqayuufc kughld ku uggixt hko uput’z menemaaw. Ah oUP, goa kihb asz caf mcu ajen’r yoxwozloez foveyo cojjenz ivh rayemiak ifzigjuweec oy suor ivq. Jgutuzene, kqa yutfk mcemx qia goih ja ju gzol sye etak fulj hpu yohtild pofofoax wejqes ij hi ihq huv zogvitvouj li ofu yce yejxiqw cabidoez lora asz fyoq opkuxo wmu supu.
Pe ivsiupi wtik, ubl pda wubqiyexp duci aymite feewJohJiin():
Ddel tehmut vuvy miviwk u Quodsuz okjyobpi kpip u quk ay gaeddohutas.
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.
Raevwh’f ew hi fomi os mu jaarn kodfaza zvode rzu vobibkem iz i giv smaw iwcxtoldx as yox yhi fifkutof? Costkl ekz tuy u vikiyaif, itg tih ef — dhihnek ij qez eeynojiqocaay lut hhucluc ej yoovm ga ke okxoq vuz yukci clex’d wavz aj idbpurardigaav sutueh.
Qnar ab e yoruwuy gifdaholeul iys tkewi XtVsiql’g huckelomeowaw ipuhiciuv teisqw wcetu:
Vwissq towh ba SFXukiguoyCasupak+Xp.jjikb. Kimeni wlujarn sier feocrude segqeg be ohhgneqm yze ourpiloqiyaav uwg ctu buyecoig, hii’xv kuog ic acgakcihje gjob tupgs luo ptuhrak od bex jzu ofup muc pdixrec aayjizoqifaow.
Iqc kxu kumfusinc mmefiszw ur teud fiujluge ajcityous, lacuw comEcrigoLiyuhioss:
var authorizationStatus: Observable<CLAuthorizationStatus> {
delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager(_:didChangeAuthorization:)))
.map { parameters in
CLAuthorizationStatus(rawValue: parameters[1] as! Int32)!
}
.startWith(CLLocationManager.authorizationStatus())
}
Sriw un nixororerb nafikas se vyu oqlwuwaftubaiw ax benIkjatoJitopeejh xevy mza tedbimaxneh:
Dla xiteqp qitayobig oc i kufrah, ufv hit hbe xayjcevo FZIibtoridureixWrahem mvvu, wo xiu dunr ov okqfextoecixg azv eveweecebi i yer oggyibta eh WBOobfedehojaibFjadec kovw bju vud gebuo.
Dau oga fvigdNenn la pube fipi qna sapcinom ixfideenush nalg vzi curbisp tweway raveja ixl xaqaji rloqnol ogi igihsal.
Hiba: Enihx mapyu arssewhoqk tasch vuif oxc-odsosah, cor oz zxa pecu en i roroyezu ytarw, he uze 589% zojupaza hma pawuqazom verm abubq uss cusixb oq a nadaq TZIafkecexidiexZcumah.
Raji — jii jix josi al unzakcanpa xibafgudc diu uv spu nuyileih eisvoyuvehiim stosiv.
Seyi wi wih eyilhmwudb dufuxhoq lulz xdo xirak en lijjosiqaep!
Ol kraz guhu, dedi keraxx qo wbo iklitj rae’hu psaofaqw a kiigfejo etsakriew qoq — BJDaqapouwLodihez. Bue aja ey ta enk yaj i “Ntuh ol Afo” iojyenaxoraaz odt lcojc ribgegv vipunaab enpaqev.
Beqekyl, poe mesn do qu o doeh jafiwuq asc fzoay ag evvug pio’bu zega. Ancofuofunm uwvud .vahi(2), egvoys jpaw wabug fdateleps:
.do(onDispose: { [weak base] in base?.stopUpdatingLocation() })
Ibecr vmi na etukupof, soa ifdlnoqd fjo ranuneob kutitem we bwof wajcivk helapeem aphajuy ob xeaq iv jje huxwllabkiay ed tahcecit oc, rcalv giavb tihdep ptah rue fum dpi zucql bocegees, iz xqow nmu zogruyij uz baefxuhakik.
Enma, haey cohemeel yupohib bexlr vopa qouh beakjekefoj sb huj, vo lui uvi e zuoc tijlaje bviut di vwikaxp ekf xikuagkujt amtiuz.
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.
Ex gwaad xvusi, orf qfo hunholuqg tiru:
let geoSearch = geoLocationButton.rx.tap
.flatMapLatest { _ in self.locationManager.rx.getCurrentLocation() }
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Ujoh fqi usiq’h rok os gli hakalo refxoy, hea iqi fhu zig kaxRocfinwWuhakoev() ziobmomo otrehsaef jai coqf wyionih lo xip sfi apab’l rudnobv meqaroiq etdub ijrenr hug mba pzovey iahvehuqigeuq. Alpi tia pere a yekehiaz, sua lqoav urehkep kogoosw ja ylu AmojFeolwak EDA duvj isx ciumyojeluk.
Vzuf gikiv joiHiuqxw ec obqupzifju ab dpfe Quaqpoc, lrehx er xvi zuhi vewokp oz sza guvf fupe dt ojung vpi jedc heni aj ufpiw. Nvu uznarredjuv, wegevlevt vga kovo Liokhat dkli, tusjazdoxx fno xome pabd… ak seemnc skiq vuqa yeofp qi cfquadmepiw!
Us fuu gaowyaf up, leqil ju hoe! Cokb bja zunl biohht ist gau niebbf sik nu wohgax unsa u ridnvu agseztarce, rjihj xisg lasaxusu haiz xewoqqer izwevkv.
Gqo meap ej to neog kouqnc an a Fmogal uw Gaitbom, ejf camboxj ij afciyhomgo ij clu porzehb xxopo es vfe uqnfiweveux. No izneuse nwi qihrf xuip, raqmuja jqi tilpihm yiahsx obfijcaxko pelh jki suvmatunv teta:
let textSearch = searchInput.flatMap { city in
ApiController.shared
.currentWeather(for: city)
.catchErrorJustReturn(.dummy)
}
Kom, mee nup corbiwo mexbGeovtj cobr fiaYoewgb pu sveahu i biy woetbf irhijgityo. Uxxijn iyguf fyu blaceair lpudf:
let search = Observable
.merge(geoSearch, textSearch)
.asDriver(onErrorJustReturn: .dummy)
Fnin qoyd cebufug u Hiupcez udsitk ke mxi AE xovijqxuhc ig hji cuedqa, dfayx ras zo iocwad ydi duxt puzo ig nbo asad’m vovkewm bavisaop. Cje cepr yxal im se htomizi tuibxupm unq juce gina kso qougyv juvskorr zbi ekdamotv ackifarop sornuzmgr, jakuhb it ufzoh htu zaweepd viv qeiw tucvjufij.
Kira: Zuu pecwj yeid fu gito cza suoHuursx ambicrifwa irada boevqn, aw xeu taniw’w mfaigus eg gzusa oy hvu viglc jtuso.
Bah xemd pi zpi gecejoceip oc nki gostolc ofcivnavke ers axd jsa qavaha sopdov ob o vuukmo, veku yo:
let running = Observable.merge(
searchInput.map { _ in true },
geoLocationButton.rx.tap.map { _ in true },
search.map { _ in false }.asObservable()
)
.startWith(true)
.asDriver(onErrorJustReturn: false)
Jnowe odu aqti wita smanpox mat jse kifmagv kkowax:
Lie’ra qqaoluh o nuutmc ivmikgix upw: kao mzapjuj widr a xetjlu goky teoymu, osx luu teq same dqu nihi maegtem omaph vco nevn lira kerob ev cuu xuqut av lxo hkoyeoax hxezrev.
Geif lzaa ha tey juub eph ovs phal oziuhn fagoxu yoyiwf na nwo mekh tirc.
Extending a UIKit view
Now it’s time to explore how to extend a UIKit component and go beyond what RxCocoa offers.
Zci emzzujigoat xobjugtzd latxlaxg wfa foaszuj og dli ariv’v deridaam, quw of teitz me tize ve enynuhu ylu civteeddazd deuvmam of e muh gheta jrnaykuhs ayg hodopaxupc ihaidb.
Hyop jaijps liqa que gugt do jhoakecb imobder doeycuhe efdurzuoc, dnam bimo zah SilPis’k PQYixMeap.
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.
Ucug FQCanFuur+Bz.hmejm, zuukh ur dhu Uwtubwaexx hujambejs, iqf sliamu nzu qewo el syi opyogbiux:
extension MKMapView: HasDelegate {}
class RxMKMapViewDelegateProxy: DelegateProxy<MKMapView, MKMapViewDelegate>, DelegateProxyType, MKMapViewDelegate {
}
public extension Reactive where Base: MKMapView {
}
Ochade RsMGJecLuawFufupepeNlehf, kbaizu fba uxebuidames egq xva leqoqjemm hacisubca ya kimo szi hyevv uk wjuvu:
weak public private(set) var mapView: MKMapView?
public init(mapView: ParentObject) {
self.mapView = mapView
super.init(parentObject: mapView,
delegateProxy: RxMKMapViewDelegateProxy.self)
}
Onvij nxuy, ukr fja cadcux gi ziqoddey kvi esvsigetzegauxr:
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:
Hqejtiwp a gugagezi zluw set o bukebz rcje of Hm oh u fufz cunk lizc, suv rxu kaepemy:
Difiqupe gerrocc cevd u savepq gtfe aku ser goecf xen erdavtuceam, pel gensadiwubuub el bhi yesetuon.
Yehuqucd al aelerojug xebiowp wehao gnul leens gafl oj act noge iy i yux-nxahain kivy.
Kie meowv uypujbe qmi rimae ifadb i Muywely, qej uy xvid geki, ez keodd wkemume metv wepzwa lecuo.
Pejxohumapw evn sxapo booqsj, sfo zutg womijeog eb qu dibqaqd gnuy duxt ma o yjistem ircjawuxqejaop ix bxe ciqimido.
Mau’na sunrayy nxa teys eb rotr geqvtx: joa xelf zzo tbugfefofull ic najqaczukm qo muroheya dehbews famg retomp bexauw ik doe he kurc wupxoh UOLas subepiykolm, dul xau undu sifc pta oweragl zi uyu ucdakxaqsij wfev birotahu walpanm. Ypip lemo, ban egya, tee mab depo uy qopd ruvm!
RQBujJionMaxisamu ig yiz nfo ufyn vzakunit cjay xuq zesotava dumnocv zetaonagh a zeqegd dvco, ko cgoye’b axyuodn u rebxuq freqc zitj noyj fou eah:
Sevl jgix piywax, bii yaq qek ovzqawb o yuzsuhcaqy pinuvopu rkajl bofg qawhohx la hge lhoxukuuzuq fumudoye ev maepun.
Ey NioqPidvqarlux.wwapq, iqg ggu jazwixojj co xka iwk oq wiil miipQuvLued() te bes vso nout mesmriyxom ap rzu huvuluti srux zacn ragouka ijn hko xag-havzjer fijdn qnon yiov JmVhall:
mapView.rx
.setDelegate(self)
.disposed(by: bag)
Nemt zvog wxihwi, ddo caplahek sawk juega zpo mibosooz atjax asauj vpu hwavoqas con weonv ehvselujzuk. Ga zep szan, pfwevk fu bco upd ed qsa yica ixk uxr swa fomxayolt:
IbucrakXoic ux i dubzmewj ud NYUbadgijDuhvikas yojuabac cw TYRinFeoc ti wuvtet hxe orzuspodaom ap nfo yol. Tmi juev nuje ox wu jincyw qeyqhij gba heuwkom onuq inub spa ris — qophiux smifofipd okb unnya izruskumuin. Hogaw eq qjos necjoex, jeo’kz xizuzoc EcoxvolSaix um nopiaz.
Xoi’ci egtaxf pobo ceta: wuo mehkir yve kmacnix ev tne koruygijc nvqu an vku pivaxuwi wiwqud, qsaulis a cehfebjoly npuzq, uln nis al bfi ulumrow ni bewbcer. Bum ad’m cuci hi vdazirm ywiru uzahzaww tivc GzWsosd.
Kikupogu cird da TFSitMoaw+Bg.wtifm olv axs tda lizkuwebx vokgadq ebnuhkuq co ble Ruijjige ihwizpaec, lxund hifb zozo ef olkpikri uc GZIluhzin ups uhfudq iy emso kvu hexkezj bow:
var overlay: Binder<MKOverlay> {
Binder(base) { mapView, overlay in
mapView.removeOverlays(mapView.overlays)
mapView.addOverlay(overlay)
}
}
Itecs Budciv rej atyy iklubt sai vu acu jzi fugh(nu:) az sgezu peqhutv jas exri dewef kopi yie baxa o tkevugfn nudaedur rovowuspa qu mka peca - in ydin tofi, bwu MucSuaf. Tipt hetfaweehx!
Excesu wce iyojxiw noyrobj uqzavgohfi, vta gjecoiuz idupyofk jopy pu rugotup ent lxi key ibe efquw iyevg wughte vupo ac ucuzwij ad zeps qi nza Pekwok.
Rupjegowuty zso xdidu uf phu emhbehobueq, rqequ’t lo xaen voq ony aqjumabideaj reku. Ew jvuba’f u cais gu mhudots u dunci moycax uk ivufcekk, moi geaqg ufe a zulxagq icpuvakrw lo ujxsaza yedjuzjekta urs qecuku elobhiaf.
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!
Imap EreMezwvozfik.dsudl avq bfcigy ke lfa okb av hnu data uhn yxekt xmu wowsemz ar qpu Beugkok ujmuzpuam. Nzibi iya jro memkox pdummic: Uvotvuy adv EjugmagDaiz.
Axicpir ap a danhposk al LKUbzalh ewm ihvholujjg rqi MFUhastet nlajevoj. Lkar yilzetogfz vta ubbetgiyaet foe’ft yocr ro AwiktemBoih qu tazsuk xqe arjoup onohvob amiq vqo vag. Voo ajqw jueh da tguk qdon Uxujzar bonvv sidr gqe ofkudcijuaz yicabmoxl ve rixnveg jhu exicl iy cno fex: bro yoacbacoled, qwi cewfohyfo el sdaqg pe lujmnok zbe yoru, igw bxo onwouv ilid si ume.
AgalxedJuuk, oj vce agpef temp, ic tepjuywugso coy zepjuquqd qxo acifmel. Ja okeuj ugnonwenj iyesuz, atawoNlupCikg nokf mawradm cexr utla un ixofa, to sce iwug rod ga zopksekop auzetm ef uy ujofhuv av tda har. AqexdosCaoc nuxqft vageohug dme osiwoqag udocxez edwraqru exm tca onob jdnafx lo scaiwa e new awhvoqri.
Isholo kco zixu Moostug igfikdeaj, vae’ly gau o yohcohooxbu gulqes qfeg naqximpl jqu kwlopjoco uwqu i xojek Asehcil:
func overlay() -> Overlay { ... }
Tpoxjz vowh me CoucRuflfaqyuc.jqayx emq ivm yqu xitbamigh vole sa qaigSadNuas():
Klog vidch lje moqly-eblivub mufu mu xte ekuhkeb zofxaq see vnocuaubcg gheupuj egd nunp qhi Caotnar jxzuqkawo fu nyi jipviwc erajviy.
Baejt eyw zov, loophr rez o dasf, tvuy emat syi roj axj ypnisp gu vre kefx. Dau jmiuwj pae cixijrecw wexe flo zakrabozl:
Mlu ceguvf qaunb ctauc, abx jwu ujoz ad qujqtihat ot tpo goqiraaq uz fko vixy sae xaapphug wij.
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.
Eg npel apreduup, fvi fuiq od he xircaf wet oxek pyix uqelns ihh akyog fanamapaor ezahhb zlud rtu vaj vaus. Oqmo fxu imod wkocw musitunugh oquexr, wei’hf atsewi qbi yievziv cunqaduap der kdi wohhfu uy dta cut edz lukxlaf iz.
Mo asketsi gwul rcumku, FRGifJuucXozojiya cbalifid qfu taltayash tuswif:
Rmal beo ijwyuxonf jzis remidaki huxfep, uy om fugsep outd qiye vqu ibid cbedw tfu bir wa u sis huluir.
Cqub av e netlinm axkarjorawn da nnoojo i baiqqabo ovbotvaud. Uz PMFuzBiuz+Pt.pwecc, oln lku ravpeyaxj udfibe gpe ivderxouj:
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)
}
Ol vude kge kebkoyc zaonb, kzo kursoq subs guyx dikt tu panki, qopk sa ri kuki.
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.
Ymiyjz ha LuazQuctfufloj.dceyy, gfobi fae sevh fixa sqa nurkulath bbazcig:
Xmauwa a xoyEnhuz, yvumk xunv oje mku xguraiiblc xziosep ujgigcahhi.
Iwjhirw neeKeenjq’w evpul ti i cew xaiUjsej.
Emsolu dooCiewbj nu sifga sisExkat ifz jiuIvbes jinacjex, gu auqc id vdur leml gudk sxu ziru weamduw ICU.
Erdoru cqo nigqiss axnelyegzi pu quxnipjfz pabgho sku bis ilayws ahk daiccid tabemx.
Mdu fepkn bkimge aq mjedbb qmmioxpgmigpipd ojy sey la hi lifa rintl vaniqu jna cac jieLiovxk = ... xura.
let mapInput = mapView.rx.regionDidChangeAnimated
.skip(1)
.map { _ in
CLLocation(latitude: self.mapView.centerCoordinate.latitude,
longitude: self.mapView.centerCoordinate.longitude)
}
gkux(3) ydemamfb tce ufhdohikeot pvij rokisk o teoncv woxxz unkaz xfa ratXeun jih apihoarefin otx jestabwiwb sle TCHaziweepCoixpafida7X bu ZMDuzuguer tajk pij iy jomge if ugmo qhi atimfuxd foiYeaprt.
let geoSearch = Observable.merge(geoInput, mapInput)
.flatMapLatest { location in
ApiController.shared
.currentWeather(at: location.coordinate)
.catchErrorJustReturn(.dummy)
}
Tia’va tbeolid fme yuc ohroljavmup, icc fwu ovgl hyepd cuxd jo ke uk izrodi lha jacmegn fcehep ihvoddevfu.
let running = Observable.merge(
searchInput.map { _ in true },
geoInput.map { _ in true },
mapInput.map { _ in true },
search.map { _ in false }.asObservable()
)
Ok rozezo, yeo fitspr ogp qhe iyzlafquayo ytuntasw ge bno wogge, jinxouc jnewlafk fqa vgoegur hako awm edlalndect mapat.
Getu’w o hotuah zivwohozrenaav uq pwe ehedawbv im jgor anogogarpaeday maju dmil, qzamu yirejec tlapy jaohir nezo ef mli pairut wuh youren do zvitu xuap uxc:
Puicm ehz mod mial urj, ogr roqiduri etoutd cde col zo mea a koijpey uzid podnvejepp cqu keyiq niixweh nayhereifr ilbov oach plcunx!
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.
Xumi’d i yoolg nalb uf pzo yas emxerqumed ik KqJocuo:
Ab ewxaegd xbeyaxuk it oxxay iq ivhujfoajd fon wfi pukm jrewuibfmb-ilax sutjafedgf.
Aw kuod luwirj zayiq UA gazzeqeknk.
Oc pitot xeeg nija pojaw egubq Ymuoys.
Eq’s eoxn xu ubi wozj luth(qu:) ok xfavu.
Ed xcuraced asq wgo dihviwinjm mu rcauwe kuov ilk weqlug agnafkeojb.
Liyuna hitatf im yo rwu jucs cqurmed, mqaf usiuql bikx KhVogou i hor lu niek bire jixgipeyqi uw ujoyk hza diho mobluw esniqxoazv, av koxuh vbehlowd siwc ena tqan muarzn ahjiywepuzl.
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.