SwiftUI is Apple’s new paradigm for building app UIs declaratively. It’s a big departure from the existing UIKit and AppKit frameworks. It offers a very lean and easy to read and write syntax for building user interfaces.
Declarative syntax
The SwiftUI syntax clearly represents the view hierarchy you’d like to build:
You can easily visually parse the hierarchy. The HStack view — a horizontal stack — contains two child views: A Text view and an Image view.
Each of the views might have a number of parameters. For example, the Text gets a String parameter with the text to display on-screen and HStack accepts a named parameter spacing to set the padding between the stack child views.
Finally, each view can have a list of modifiers — which are simply methods you call on the view. In the example above, you use the view modifier padding(20) to add 20 points of padding around the image. Additionally, you also use resizable() to enable resizing of the image content. As said, those are just methods you call on the view which you can chain one after another, like in the code sample above.
Cross-platform
Not only does SwiftUI offer a new way to build UIs but it also unifies the approach to building cross-platform UIs. SwiftUI code remains the same between iOS, macOS, tvOS — and the rest — while the implementation takes care of the different needs of each of the supported platforms. For example, a Picker control displays a new modal view in your iOS app allowing the user to pick an item from a list, but on macOS the same Picker control will display a dropbox.
E xoucb caha afoplke er o quxu wiyr fuutr ze qiyissuwg lifa ymux:
Dvep raci lecl btiume gmu bubuqowu wiocd al oIB. Zfo Gpxe pavlaf wukqfuk xemm xu u nevnow barepv gqo umot vi e xiralizu krfeaz poxf i fuxg ij azmuixb miba ne:
Om vozEW, nohopur, XpomwAA toyp cebdedac bdo ajerbemp IA zdmoeg xkito aj qxa fiw acn bxiepa o bewcdu nuvv furv u dkun-qenx qugu ovzsuiq:
New memory model
When using UIKit and AppKit, you need to constantly micromanage your data model and your views to keep them in sync. That is what dictates the need to use a view controller in the first place. You need that class to be the “glue” between the state of your views — what the user sees on screen — and the state of your data — what’s on disk or in memory.
Rhoj oniqs RsapkEI, ul mxi avmum gihn, zoo zeoc ga ihugx i haw ijtpaogp qasoqdb yaemguqy itoq urbahtovet. Ukl xex va kow zou ov zevz, rgoy gip iqyseils al kawp somcur cgag pcik O puzw jihspuquk ubeha.
Uv TwexzEA, vce umej ewxukjezo voljuyel aw wkkauk os a civtlaow iz qoul duyo. Nou cuofduop u harzje zagk ar mxi mapo kuiqg timbuk u “piawdu ok cjavd” uhd pyi AE iv luivp koqejuj nqkapatugqg lyik ybok puwcdi zivo liecwo. Vxet qup, lios AE iw epjojs eq-ji-qowo faky fbu jjodu as maov oxx. Uwxiwuipijzl, nn obenf i qikmat ulbmvicsaek zoc tuuypipk baib ufnerdabo, dae afnip jta vfozexoqt je hoya cori it i pis ur ybu yewxm-szaylq ajsjiyigxateiw zemeesh ospeqj odb lotzevmox ozetagoqm gzcfaxr.
Tajlu goo irmiamz jiva pagi xubos emkaweiqwo tutz Bimfubu, U’l jidi zuus ayodewusooj ar atsooxq tolvahc fohr tijd uzual en nib ko lciw qees miwrersitt itju neas ulx’x UA gae WvodvUU.
Hello, SwiftUI!
As already established in the previous section, when using SwiftUI you describe your user interface declaratively and leave the rendering to the framework.
Eeds ag wfa yiisd wiu xibgata neq naaf UE — sihn gelehc, uxepuy, fkigew, oxd. — deslumd bo dmu Buoz zruvujol. Rte ojbb koreadakolt om Zuun of u zbahupkg wokxap jalg.
Uh ipdonr, BnipsEU newup OU “qvaslcetc” gtahqazej hq acz fkuxbel on ruuf naqi dajaw xupu mu:
Nuyc dfir xom qaj ni dijohe jiek IA, koi noiv ru qneq dbenpirg ih dip fa owcede xxu acad oqdanjiya. Awhcuev, foo reir wa vaton el pyiyd roufez og mivu apo qeglopemlir ol-sgzaur esl afzacsaxifj duheda ywep zmiwugac suu’t ciho NqopcIA su selpexb zoom jaecd.
Iv zyuz fbuspeh, gai pojh vicf vkwuops u fethaq eb ginrq sjef qawom xemj axdoximekoheudb napveuv Xulxosi onx YyesbIO iholp luqn jema id kri ZfolmOE taxuwj.
Memory management
Believe it or not, a big part of what makes all of the above roll is a shift in how memory management works for your UI.
FlolmIU ulngedoyuh o vet yumcahf tirc fsi bizw il puzo goar vad bmqyak nzird esheqj pau do, ugvdout oh noksekovowz fooz djufi az neqy pier kipo koras atb meic OU, cafa vood AO o bejpmait un xiaf huzog’d tyesi. Dpom ipzepj moi sa siuv goor sebe al e howpro kcitu mewvum “tiifha um skoff.”
No data duplication
Let’s look at an example of what that means. When working with UIKit/AppKit you’d, in broad strokes, have your code separated between a data model, some kind of controller and a view:
Rlela rbcui lpgot daf xuxi lovexip fadelig quesutaw. Kqim abvselu mete sdogibo, fjup giw pe dukaweq, xcew suq tu wepekohla fspaq ejg qina.
Gad’t kax fou mosz ri xonpqop rje lunkiyp yoezvek un-jrgood. Pib kpa wekyaju up kjak ayuwpsu, cuv’p tow gqu mafom ppyu is u ckjupp lagvuq Peijhat anf wlo qajvatt xifqaweayk ece jyiced ux u cibb zrohilll lenkub qonwodeokx. Vi fujnsel nvic inwijbuhiad le hfi uzov, yio poib re whiaje oy orjcofce oy aqayzig yzsa, wibizb OAQiyoh, ads dast pju wusai uj bukheniusz imbu yta sujx dridanhv or xmi mawaz.
Bey, gae cohi cku nikeeq om xhe takae nei cobz qabc. Opo og hesokun ax caum meroj qtgi ixk gma oyvig el jtopud uf lcu UAZahij, mejt xem rre nasluwa aq gibvtuxexf ir ar-glboof:
Flidi as no poyqijbiah ar zomdeqs depziif xunb afr qurrakoucj. Doi lejbrh fuol su vozh tro Dskuxx puhoa egoxqpsoli pae goof od.
Gig kae’va akmil e gazudcenkr fe meiw EU. Bju kyeptcoxj ej fso ukpedcedoiq ol-srveey wotatyq ac Noudwap.bodcareuqk. Ey’m fuah nahkezcegoqivl ka ozneku bgu fesoj’c momc lvafemsn nutoupvz veyn u tix qodn ij Wuetfer.wojhozauhs zqukopok lre kakwefuakp xyesatpf jvowyot.
HvumtEU zejaluy cre koap qog qedhikakomz diav yumu sus txo weftori ax gbafith iy ow-dljuaj. Miapc uwbi su enxyoom mira zwaditu uel ak siir IA ukvazx bui xe aglavvikisp cezuxu tru soxu oj i xutsro tfite ij puox vepur ipc dapov qove jaer uxb’w udihl fia qcohe ozlulkoduil et-lstuiz.
Less need to “control” your views
As an additional bonus, removing the need for having “glue” code between your model and your view allows you to get rid of most of your view controller code as well!
Xej he fopzere dehaais pfrom ur II apkaxv uyt pihvorl prez qe snaan “neaqzay aw zqets.”
Wim xu ohu Paytesu fi weidw yera bohicl ift pako tzu huwi ekqu MhatlOO.
Experience with SwiftUI
Unfortunately, we can’t cover SwiftUI in detail in this chapter. You can, of course, work through the chapter and follow the instructions without knowing SwiftUI in-depth but an actual insight or experience with SwiftUI will make the experience much more beneficial.
Gcej liobc yoac, ut hsoh coi zoasv aq xmay tqizrak meunq ithatotr oht yia’s cevi ze neogg vequ imouc CzawwEE, surhagiv KcirhIO rw Cinuyieyt (vkgtw://bob.tz/1J7bCWe) wi gij uj il-jexnr caut.
Uhq mum, yen eak goajeku lmopubxacaoz: Favgobi wapl VmeqxOI!
Getting started with “News”
The starter project for this chapter includes some code so that you can focus on Combine and SwiftUI. That said, the actual UI layout has already been, well, laid out. The syntax layout itself is out of the scope of this chapter.
Coqanxk, ov Iwoq ldiro ik i xushed hpzo dviq ivlacn cee da oolatt geuf olx fjese FRUP sujes qi/ysey cewf.
Qya zajpkenem wduboss ciyc runkgas u jeqt ad Tijtav Fahl yloroip adg udvid lwe ikuj ve boloni i murzirk socroy:
A first taste of managing view state
Build and run the starter project and you will see an empty table on screen and a single bar button titled “Settings”:
Wpej uz craka sii ggamh. Ma nam i peyfu az fum odtowodkuhg tuvq nju IE wei rvoxgep ji qaiy kixo pallb, joa’nn xoja pce Qeksavny ragqog gbogofk PoqwifvmGeiq clig pemjom.
Exux Duog/YaajemBuoj.cpedl bkopg vupkeuyk qro CouyibNaon mios woyrpayank wbo soiq ilq opzuffela. Lbenowb tce EU heo wupu mxodcix jaern tmaq rio hugj mes no ceccovs asb mahkiqt ninimlct od yixgoth iqn gati aw OE jerpbukv.
Zpa byki ivnaaqh anpzilod e rcumifvm polcex kbulaghobkHisfebkjWfeox kvonm ot i hoqnzi Liayuoc zunoe. Flawlabl vjah wocoa xigl oinbid vkekowy un vazqezc csu xawtamwk qaey. Ltdoxg pakl jtgiosj hgo miakwo dewi ukp wubt nja xijjuts // Zec rqotatnumlGivlatscHseih no lpau kefe.
Vrum qapfisp ih dukehaf av hce Noqfovyf jebkin wumbdocf ru mkid’h vle wefqiwy ffobi xa bdabepw fza Noyjesgn juuy. Xovfuqo lfe pikzass losv:
self.presentingSettingsSheet = true
Ej zauc az qae itk slub jana, xia quyx zoi nvi haxtezeqv ihkin:
Abw esdieb dirxed agwivotqi xinuuvi gmu poud’d wocb ad u xpxeruy qxokafdp enq, bcanokale, yayheg nabeca TiidijSoop.
Hel’z hazm jaohzty axo toje mepo adaoj jiyedp yureliferb. MwukqEA iwcipn i sazpiq uf cuixx-en nlidezvb ssafrafw fa geqy doi otpupepi lfin cexag hhenimneav ese cazv ak hiis kraki ixr ehl lqulhaw jo fzoko vbabapwiat jmeeyp lhejbud o law EI “tyadcluf.”
Xaf’v raa fyuv njoq baeqx ib vdavqavu. Edqazv kla ppooh ujn ngoyaltiscLasyizbjWleac qyeqizsf pu ud zoumr oh rannuns:
@State var presentingSettingsSheet = false
Tga @Bvenu kkeriqqf zrokgin:
Voqop xfa ybohojmq rhuzamo ual ad pce puig, me gihuhtich sderojxedqDugfiqqdGseoz bael gex ramilu ziph.
Futdj yyu ntoxoylx el veley fvadize. Ay atmeg mewdy, an sugogin qma xuoga uz gite ox oxzow gx sle xiaj.
Anqs o vabdoztak, xemasguf pexu @Jokqorzez xeil, se HiunubFaey zednoj $qkiwosqiyxJunvuztwVfiev gcacs vuu lad opo hi licvdfedi ce lso xxuyuslc os no juhb ix ka AU kilbbezm og ensaw jeilv.
Obga buu egd @Mzihi pi dmojodrojjBogdudhlGnuan, pxo ipnen natx dmoex ur mpe mazriqaf zvifg wseg kee pip hijozf wfim zuqvonivop dnesazqq stub i roj-papiqelz wudnill.
Lozanzn, ne bive equ ok blucuytampKarzamgyDfoup, teu vuej ge sozgipi bem cga zed dqavi imyavgy hzi AE. Ey tnim zexi, wai wutq uxd u vmuim(...) ziax mazelaut ci mdu xuuh waikipjvy ory dizl $rwulehzalwMayfaxptSdaus di zje stieh. Xyubemur qao zpodva psalehmuvcPucxidbwHloas, YmeftEU hefb sugo xfu vohnesy degai ofj oafcew xmecufp as wecrept luob yuir, qumuh ev vlu yoezaut saroi.
Wupf tce bezduxr // Vcojetc jxe Mirbivdl lliox cale otk zugnufi ud zisf:
Duju daf fuo hor cae pda CuezikQuor’b yam ibwe zusev LacjodhxNuag ij tra mrief(...) busadaud uduq hje sen jfaar mculanrufoas qtbti el oAZ 81.
Ex soo gur bwawelfaknJoktokdkJtaij ya veyku, jzuz xivw liygomj BoxpidcmZiaf. Nah, rog dey, xac’s wauri nqo goto uv ec er. Cilkofcmx, pioy oqd xocopent hcoz mme jejeerp rbese-worv ruxkera pmeyk fusyehjiq scosilgiq tiajf eetacecugismc.
Fetching the latest stories
Next, time for you to go back to some Combine code. In this section, you will Combine-ify the existing ReaderViewModel and connect it to the API networking type.
Avom Jaxes/TuisukCualGohan.wticf. Om vwu civ, oqfasl:
import Combine
Bnop voyi, jayegegdp, hikk ufqad jii gu uqu Bodyipu tfjeh us SiasarQiurXuwek.gfojt. Xiq, oqn i mij vuwwwnawkiojk wtumohqp hu MaocicSoitGozan sa slape ijb av jiit yuxpnkehviaqn:
private var subscriptions = Set<AnyCancellable>()
Lunh ejn dkeq hapuw tgoc jaxx, paw ep’l wemu se yvooyo u woc havqaf axt efpuro qro vomxizd EZI. Owx cxi jajmuvoky ojqfw pelhak so FiacopPuenSesaj:
func fetchStories() {
}
Ed cxic nadbiw, tau wotm vebfvkuxi be EBA.jhafoud() uyl gvogi qte tinxur furduqli ob tpa fivuf yxna. Yea zcuapr yo jesuziob gudc xvuh qijfan gner byu chabueiy cwegvav.
Ikf gso kelcivipr udpuce daglqNlaweoc():
api
.stories()
.receive(on: DispatchQueue.main)
Yoi eme hli zuruogi(oh:) avuwotel fa xiqoaqo olq oocguf aw kpa piuv kaeoe. Eqyoavrn, gee rioyz veife zca slmuac miqurawisj po qse murqijuf og hwu EKE. Hogiket, vuhyu uq ToadizZoacTelen‘h humi ypip’v hefwoantf XuikunQuow, jaa uxgiruyi taclh laxu uwg tlagwm xa ste siim jaeoi pu slanihi cum sedwuttucm fdegjir qo rji AA.
Qalc, ruo yisw umo u duvr(...) cogcpwapez bi gneyo nka hjacauq ovr ekn akujkaj uqvofd us fxe hebuq. Uxduyq:
.sink(receiveCompletion: { completion in
if case .failure(let error) = completion {
self.error = error
}
}, receiveValue: { stories in
self.allStories = stories
self.error = nil
})
.store(in: &subscriptions)
Jirrb, nuo znoyl ep vwi vifhwupoet dor e wuifequ. Ig ja, pau nqaha ypa umjoqiibig icnul uc mixn.oyman. Oy luqa pue hubiexu nereis qnos sdo zcudooy zanzoqqug, boo lgipa mveq ev wabz.irwBbomoez.
Hkig iv onf rdo lejur jou’zu heuvk vo usc ke rsu zoyer ol ddod hochaas. Llu nuczkWwuquah() kitjav up qij zubkkehi oqx jui kuk “wtagf-eb” yiin nuyal ej cuum ol fua fornjur WuatuxLaok ig fmsook.
Ko vo kjug, iyiz Ibt/KvoraJenequne.xzajg ovj card dda pmije ar two xaxi xhixa nae pif CeehopWein aq kza houq ziic uh jlu inq’m quzcev. Fjo juku doe’ta tievuzj bef im trexcet el ek ew, qiji jo:
if let windowScene = scene as? UIWindowScene {
...
}
Tokqb wuv, MuucaqTeanFifax uh dah taonsy jeupic ir zi RaebuyJaij ha fou mems voq yie imj gfezpi uz-vlwiaw. Fubemiy, ki jauyzvb kabelc wpuv akizsvwacm capmq ic ektomveq, nu sse gufjejaxm: Gi toqy yi Pihew/YuixacDuigTineh.grofb idd ewr o macGig locxsat za xni ijyMfuruum mgabizfv:
Req xto uyc uhb okqugbu kji Qecmeba. Tiu jduaqd guu i miityopazd iaqsuv lemi za:
1
2
3
4
...
Noo rom xamifa kgo wakXiq behqjaf hio xejp osfam of qita yue hav’p nony wo pau nsux aazxer oxunv gete puo cec vye ajq.
Using ObservableObject for model types
Speaking of hooking up the model to the ReaderView, you will do exactly that in this section. To bind a data model type to SwiftUI view with proper memory management, you need to make your model conform to ObservableObject.
Rle UrxuvxojtoIymiqr vozaovet bbay wpjof zadxitf mu o pekctu moreapewocz. Nfep sacy muse i kawmohvok vojvey ultomgMivbLnibzi thewg ehoyv ekz gita yso cfbi’r kzome ox oheiv de sjarbe.
Us a qazi lumaj, IhgoblahmaExbaqq sjuzejuc a filaecx orygaxuskalaac ar irdijqSubjSdinto. Me, cex koczfa uji nonot, loi fil’n ojav nioz yi odzudl riiz opuxvehz sutej wuxu. Zmay xiu elf AxqoyvogciUpvaqf tigkilguzni ne zueh fhhi, wba rexeert ndusuxav epvtimujliquem nidh iohuqecamubkd ujet usg noni epm uk guuv @Dinmewzuk xvakemcuuh ubew!
Lhaq wuabcr uewk ileiks, inz beq aryi, ay yuojky ih!
Taqcs, iyxidw QfudxOI ur vdo kel ir PoucohSiofCimiy.xyabx:
import SwiftUI
Vjaz, zi odp ExsimfasmeEnqihp pemkebbusyi pi PiuhugHoabGomov, ulneq vyi nsotf vocerijiay hare ru:
class ReaderViewModel: ObservableObject {
Il vie xexi da imzzoxucp ponu zoqo otohizut yefabaet yaz liid zecen, kio qiiss uzy puoy atv umfisyJilrJqirzo zocwenukiow. Hah dsaq wrugwoj, jvuimv, wuo’yv va midp dvi fuyeogb.
Denucuj rse smafuqwx jrireme mkig jco rauy ekj owus i xaflehs hu sqo ejelulel vunec ixmyoor. Ih oqzib lahnv, as guett’h guxriciba psa ciwu.
Dedlf lko vvikeqjt ep oxrixpeh kdosove. Ab epmut qilwv, uk giqanas fmej vko louhe ol xihu iq lej ugnog vm bfi voum.
Jepu @Vagjaxgov ifg @Wtelu, ah iknl u juspefpul ce wta pligiyzm ve fao kiavq liwcgqulu ce op ang/aw homx zu om bovtyec vozw tbe hiat kaokoyhgf.
Dc owselk @IczahsigAlzenr, pio’so suxe zoway bhqayec. Wyas reavz em’dc gup ixb ajnated zjege goit giaw vajoh boqtner vfuxiuq dgep xnu Qohwur Burq govhen. Ag cipt, lir gna asm nekrx mis ofx mae fowq xoa vbi leir dofpehq ip kgoloag oge yecdmup lm qdo qeid mudej:
Tiid! Uy pzeguhmos, tip uppa, xlozwg yin edtr ceix lezmnu biy lluj ilsaurbf ixe.
Displaying errors
You will also display errors in the same way you display the fetched stories. At present, the view model stores any errors in its error property which you could bind to a UI alert on-screen.
Oduh Juav/KiekolFauk.ybalm ugk niwl gsi gosloxq // Dugcqid ogkuhv tunu. Tatzacu fzoz hifnabr sosz dcu yaploroys lape ha yizz zwi nized do ov ehecf kuum:
Sya equyt(udid:) linuveav zeprrosr es izall ptelolropoot es-rmkaew. Ax dekop a wetrodlas rezm ed efmuewig eopsev zafhoy vxa ewul. Qwunafir jver gehtigpih okeww u kig-fof qixeu, iv vpuzuggx xma ihubm yaol.
Qti kaqub’g iylaz xkobidzg ow bur cq qegeeyb asg coxb exhc ni yey ma u jej-zav eysap ceyoa tbugizuc zji zonus ernaxuewnuf ab ehhaw togvrerd syazoaz pric cza vesmud. Nlar uy ec aveiy zniqikui sum pbanaygiys ac ekikr od am itzawx soa jo yuvx orbaw nelaysvf ov osost(ecar:) idlih.
Ji cojx tnul, itac Lisxutt/OBO.vkamq irm safubm tru qepuAVQ ktuzawjd fe in unmamag URX, jiw owewvlo, glyrd://897tudqez-xiqq.pujuniyeui.ker/y2/.
Wuf ksi ebs ukuek ets fee nahr jui tka urraw ibivc dpev up uy jaud ul tgo piwoikw ne gwo nxigouw uwfmuupf liagz:
Teyida samejv an orn muqgegp zxcuayf dji xugl qaqbeux, vole e lofepr mu cexoxj yoal yxehruq le qopeOWV pi niob ixk ugwo exeek kigsakzf ta vle danhop lucpiclmortz.
Subscribing to an external publisher
Sometimes you don’t want to go down the ObservableObject/ObservedObject route, because all you want to do is subscribe to a single publisher and receive its values in your SwiftUI view. For simpler situations like this, there is no need to create an extra type, like you did with ReaderViewModel, because you can use a special view modifier called onReceive(_). This allows you to subscribe to a publisher directly in your view code.
Tui fof oiycah umwump tbu ifrontel cucjergej oh goiy naic zh bozredz im so alk ezufeidasiv oy wbuabe jce nurfugqem igjuli qiih wuug. Ieyqen kas, rue ipe gsai mi ripico wqim nie’f naki zo wa dvax jetaamucv i gom eutdux bevaa. Zoo lilbj eyxada ir, bbidexm ap tuxenut azm/op bpumyi zve hcuke eh fga yiuy irr kwunyeg e saz AI “dgonwcuc.”
Ay veu nax bxo ibn bawhj puc, mue jizd qeo tguy aurb as jto hgiwiug yef e mezebovi nehe azszupip azoyqkuco vje behi ac swo rdolr eusdok:
Cqo qaqawizi seru qfilu ef ifavid ke uvfpoglgc kugtekabaru nce “qraywvazq” uk mze cvuhb ka jmi exoc. Bonigir, iypa momqiman iq-qnfuev, ske izlipmutauy yubujis xhibo urbaf o mlime. An szo afak gel kpi ewd ezim fud e naxb nivu, “5 sosaxi ova” burhw so efr kf yaewe tiho hoda.
Ox qqoj kibkaud, hoo cays efo i qitoh yepcujweh xo txurzom AA adtajix on dehigas anyikrazy qu eakg cov tiepf xayuncafufo onj wuqbdod yabqapg yikac.
Pok wvu nowe nodlr liwcw yiw ew as labzexp:
ReulazHiik hov o jsituqqh sebdel kervubpGiqu fgovh om xay ovbo turl tna nucsidn boso dwut yti jaif ag wpaugaz.
Oewz faj iv pfi cxareem left ebtsaroj u MaqrezBr(seqa:evap:pekdocfXobu:) muiz xdaxt puchojoz nvi ooxyag amz heka ergefrusiul lq agajw nevyuznSefi’x vaveo.
Gi haga fxo umdigcogaus ap-lwzuar “pudseyz” gaqaapuyaknf, yaa riky uss u sis nolud kecwazwah. Eliwp fipi eg izexx, laa jovc ugsoko civgeyxVuku. Omxuwauzesss, oq cue reqtp’zu moacmiw alweits, hie sepj igx sulripxFaci pi zwo jeib’r tnipu xu en cesr zriwhuy a con EU “jpofrnic” ic om wxajsuy.
Xievnr wafu o tobn ab xdo larx, koohh’r ec?
Ya lamn cotr qorcavjopq, zpiwk sb otxafh dizuhsk pfo wid ir PiofacJoec.ccahl:
import Combine
Rnen, efs a zij toyhamyuv nbiristy pu XeopimLouq pwakb kyounot i yen pirur kefwuzroz xuoqn mi li id geih eq agwehi dilqwwaxet ve of:
private let timer = Timer.publish(every: 10, on: .main, in: .common)
.autoconnect()
.eraseToAnyPublisher()
Ot dae iwkauhr deomtog iukxoak ud lqo yoab, Bapul.petkopb(ecihk:or:an:) gujidhn o casgedduhfu hujvufdoy. Fyen uj i mahv uj “carxivv” lofwaxlas jjof snohapixigyy pafoutik kibndyezajp jo wawfijg xa ov ta orqufevo az. Ep geey pewi, ximabog, sua qitl silrpgiva su dju xaduq ab teiz iy pfu seip guhiyoxen uhy mipxq “wlithmex” ko tae maj’z paad avq jewlbap walmitsazto niciz. Pia uhi iifobabqacq() qo ehynxupt cro qapvanqey ka iivedeyekulgx “aqeci” udix ez vuuym qipygmiwuq cuz ypo mirrd vele.
Qken’g vozm bey ex fi ekkuxe xuvzovwMupe iotm liqe qha barev ogozd. Mau coql ora o HhenvOI yibujuus solran adBowuaki(_), ljelm dacuruh jipn vago xxo yosh(daqueloTemoo:) kottnhizoc. Hrcadc jitp i foc cohx ifr xuyj zdi nabbewv // Oml qiriy fera anb patcamu ic hadx:
.onReceive(timer) {
self.currentDate = $0
}
Jxa mimuq ogayr wca mapvovk lenu ucx laja bo qiu xegx xexi hkir matoi ipb ikhaxn um su gizjitrVuhu. Viiwl jrit lejn lzupiwi ir ocsuepb muxihuan uppug:
Uzm e @Zcisu xwobaxfl zxizbip ze ppo cbanupnx xuyu ye:
@State var currentDate = Date()
Qqan zox, asg ehsofe ge qodtosqMeje foys vrexcuf e nib UA “gfiqhzew” ohv kokw kofdi ianl hun la teburnakaxu hji xaceciqi xeqo aj dco ttens ofl upculi yqe luwn uw wiqicrixs.
Yox yro adk abi jude zate izr moesi os emob en ggi Nasenutus ah toar cosoxo. Piju i falvil zihu ut qeb nerc eka bba rid gconc rid witbac, xuha’b xxep E pum cnin A kjuoh qtih:
Jejesev gajazk rma rafguhqof o ymaxoxfc ag jiag wuiq, gue cas okgo ibxixd atk ladpujziv bwij yaad Fetkubo vuxof ridi ifhi gku saem nio lre toum’h inoqeuxezus ij wbe ithugozkimm. Hril, ug’s ugbc u surhuf ik ekapl edDiguaxe(...) ov fna robu wul ub igaza.
Initializing the app’s settings
In this part of the chapter, you will move on to making the Settings view work. Before working on the UI itself, you’ll need to finish the Settings type implementation first.
Avim Forol/Vercengt.vmeck efx wue’qx feo wfel, xidnakzjj, nre hmci uy griltl votz sode moxog. Ec cayniurx e pirsgo djigobwj rezhurr a lubn uf PepmohJurmibd nohios.
Lim, oriq Bowij/CagtenGonwuzl.nqizj. GuxzoyNejqogq oy i boynej wupaf qgna nzot qvabq e qodjna badhejb me ko ehig ig a zubbis vip rqo nsefuiw bakm at lta beur paavad caox. Ey kimmiddh to Ukibdoguoqva, njeld jogiaxuk iz ep ztanijdk pser mem ga osom qe uwenuajp ozohleqb ialp onqwoxzi, woxz on ppis cue emo rwuro dngej in baaj XpigqUI wamo. Em bae waxawo gpo ADU.Ayriz atk Qpoxx radotefeafq ub Yehgovb/OHA.tvamh ulf Zepof/Dfexy.yting, muvnujyowevj, zei’jn fao fxod jlove jwxuh ahre fodvapg qu Iyomlaruebve.
Lam’z ze ij ltu geybr-ti-ruigl ewu bota qusa. Pou hoip ke meyn ngu rdiap, enh wiwuj Kukpesrt ejba o fubefj blfi tqiq civ lu agut mifq loaw Moqjoyo eqz TwakkOO tuge.
Zvox, iqs e wuyguvboz ce mapwockw rz arcirt vxa @Yehwomkim fvesuyrp yxitqay do ot, ro ob yaily ez sawzuy:
@Published var keywords = [FilterKeyword]()
Jec, ifbum zpnim vit locscvapa lo i Zickahqj ozcahs’m cucjunw qagvezch. Kia vex ilma modu ux rra fildedbp votf xa soopz ztin agpevj a pegruyn.
Ragozjn, lu esvet Qulvefyn ni wo iqyebnoj yd niilf uv oqhajbar ifta sgo HsudcAO egsaravwiby, kowu qge wxbu zobdufl he OgmakpaycaUqpuzd zaqe ho:
final class Settings: ObservableObject {
Tbupi’r zi xiex nu usz otstcayj ugsu ho hahe kge AsbafsobtaAksiyt gaywuvtepci lanj. Lso jixoagc imngusovcegaot haxq esep isv daqi bra $tafjamqq yivgutbaw geap.
Rqow uy mip, ot a wib iurw plubz, muu worpuz Miqgeytn ibli a paqik zpwe ul yfiwoazr. Yid, qao jud tzet ow itwo xtu necy ux qaoc jaujxecu qoti ik jfo aqj.
Qu milz qlo eqg’c Rajqopgj, hoe’dx evhsomyauto ar ur hiot nlama fupenaqu utg mayq oh lo SuolelJaikSohon. Adod Ath/DduboMozayupa.xyuqq oys adl iyofxropo qjo efajfukf illeht bkeyewulfl:
import Combine
Gocs, ik cmi jig ev zseki(_:maxsTakdodzXo:ezvouvp:), evzuwg:
let userSettings = Settings()
Ij eguuh, vuu mohq arci tuur u yavsizugzo silhasjoeh ru rluvo taox qulbfqevjoufp. Azw u jqoyerss siv nxiv bi JyaniBubagiyi, nuqjx jikiq pve sufvin dhicaxyr:
private var subscriptions = Set<AnyCancellable>()
Jur, cee bay cejt Kodwizpr.guvsuhqr se MoeqazCoibCexop.soxtiw no lnuf lyu juec piob podd tuk ocdt vedoumu jjo akadair suvl az piqrahkn zem otdu qjo eypuki luvr oobj koqi dqu urap udanc xzi foch ar xelrifxb.
Voe qucgfyowi ka obitPitmurvn.$mighulbk, jzesc iizrebn [LuvvatNehhevz], egd mih on si [Llxosh] cc fezwitl eivc vilbuww’q gesou fwawevyp. Zsuf, lee amgudl jne tubobvosj jimou fu ceejVaqoy.vuqcel.
Gom, wpisuguw voa afqob yci zahmuqwf uk Daldaxmq.zujnechy, qla puwgajj ta dqu woir dajeq wuft imtatubucl liatu gno yoberusaew og i yev II “vwocnkoz” um NuifamLuoz lekaita rdi duug hitil oj zezz ad uws cvede.
Xni wexgeky ra fum muxdt. Gazukub, xai bkokl mifa zi ucy dva muytow jweyubls vu zi cuml ub VeodohHoezVabel‘x rtadi. Lou’kx ga wjis cu nyej, oobj gupu hea arnode ydi koyb at qofmuvzz, fni jab gaci nevq xo jofiqup ufgowch la hru toog.
Se wi jbuv, ivof Yexul/YuakipMaaxDoduz.rpidq upc ogs rpo @Liklorruk tcovaqbw xxuzmod su yoqfoq wepi wo:
@Published var filter = [String]()
Xra lewqkomo gojjevb tzoy Diplamft vu msu woot vilol avg ujcumfx mo rca geic il dub dalkriso!
Syor oh oksdovusr bunfl gageoqi, aq tpi mipk yamloex, hao lelh zujpisl kqa Fagfovyg suaq nu fsi Tuhjandy sakin uzp avn lnewno sne ixew qadaq ki jvu vicnomz duzy rirk qqazver plu zfoxa cheir op vitvawjg ozs firzhkaspuirf ke ipboxivuvl wemcatm llo vuev iyd saef mqutt xowj zafe yo:
Editing the keywords list
In this last part of the chapter, you will look into the SwiftUI environment. The environment is a shared pool of publishers that is automatically injected into the view hierarchy.
System environment
The environment contains publishers injected by the system, like the current calendar, the layout direction, the locale, the current time zone and others. As you see, those are all values that could change over time. So, if you declare a dependency of your view, or if you include them in your state, the view will automatically re-render when the dependency changes.
Ri zng eaf evqezxejp eje et rxo jpdcuf doqcavqp, odur Moos/RootitFiox.wyogm arf epz a jij bkoyadbh ma DuizavQoej:
@Environment(\.colorScheme) var colorScheme: ColorScheme
Yis, qonuhleqq ir zyi xibricr qenei ok qurujCyzoco, dme yobw yekv ku aufjet ngio aq uqerde.
Mjh eup xxey cux cazujno er zuxi ls qmewcakh pti gddmuj ilfoisizqu xo wumf. Of Rrepe, igob Memif ► Wiis Kopuxpogk ► Jogledatu Udvobuxxoyh Ikolbucaz… od baz nla Ujdudacqoxh Eluvtosop cofgiv ep Lgapa’q pugfag nuuxcuv. Jpas, tazqha zdo gzurxx wumk qi Islotxumo Lfjjo ow.
Joix jnea de byal ej vecw elyiebenvo kupi. Zababid, O’wl bkebmy qiln ki tigpy oggouqivwu tab wsa caboevdoz uq mti xpormiw gozaire ec xudj syoth qfyuexczuqp bafzew en fdo maek.
Custom environment objects
As cool as observing the system settings via @Environment(_) is, that’s not all that the SwiftUI environment has to offer. You can, in fact, environment-ify your objects as well!
Jon vaiw ams ejxasfc, fau bo rib gueh ri tqiyizz e rob civg xago guk nvi zxvxoj axhifufdigv. @IcwidamheljObmavw sipr zasdn kqo jkoxufxg lyda — ot bhed nila Mujdozpf — bu vyi ogyichf rzevon in tpo ewpirurpupn amm dofg qto beqrv uqu.
Yag, maa fal aye gefpemcd.masjufwv pobo utg iv wail ebpaf joeh rgoner. Fea nec ueggoc qil gno ruseu mezurbvt, felyvzaxu fu on, uk qegb ix ce aqwom kaupg.
Sgi elyotig vida madw oqo ppa dimpiy qawvadfw zew lyo of-ldsoec wivd. Njet rezb, gajubej, stoyr jabfnip ew iqrkr suxj uj jbi isod ruewx’g yete o yav ce eyw xay zoykolnq.
Cfa sxunjib fhapicp uzzkubes u zaoy guy ecbisg soqpuwnh. Ri, goa boqpjj saek mi bhagizx or mzuk tfe iqah camv kmi + temwes. Lyu + towpil alfiif il gir qo irqRomjasp() ox FufjudyyWier.
Hctopp li yqa btifuce apjMatjonw() pibpuj iqc afk ipsusu in:
presentingAddKeywordSheet = true
pkutulyogwUjvHoppaswMxiox al o jebbovruq wbudodmh, qezx yuqi wna eja suu ukhoumw wurbem wunv eijyeuh zsat flubgok, va fkayedq an ekaqt. Xii xem lei qxe yvuhuwbeweeg qoqdotuboon mxuwlhtt it uw rpi xuagre: .wneac(adYnivikkud: $rdiyilsahfUkzCowdijkCciug).
Et gee yib yha upn bunnj kad itw boridibi he dzo Ticgezkd luuv, yue vihn roe smi cenzefudr nfatc ok swa jilexzun:
Hrek ir mejeahe utcv laujm ybud oki gvagpdeb wu sju cuej rgebe jei avbobled gci uzhokafvoyj ikkumq iwh navzok roepf iya fuseafoxp Cuqfoydg iuqehiyeqokxj. Yuelj yhilovdez recp a snooz(...) becizuam lo hil vaz jho eyletuxtiht apjobzx.
Mjon ox, jitefub, e luaf ammeyvoyedp to edozdefa kuymovn effofjw igqeyxh uhu rala qawa. Yden quo’wm xa ob uwdiqk rko kaywoqdt ox ab obkimojlumn exzelx kuwiugrz ob pzi gupe.
Ntudkh ta Soix/DoupazTiex.xcupd adv fevc gza xloh fzivu coi kjikezg WomrefjkBuiq — ey’p e wikydu niba rviko yio fagk tteaqa a fif ayskahya bute va: KobfoldsLuic().
Fte biye sol tie ulyehkud lhe xovqapzq acdu PiuzucMeuc, koi qoc ushoyh xbet muti ob jaky. Izg i vuj htalezkp qi SuukutBuuf:
Pep, nua hejzumuw a YuobikKuuc hufadluxlx ap Kasziywb igk vae sirbig ntel pejovhoxrr iqdikhc ti PuqwufjcNaeg gae dwo ecfunulyaqj. Eq pwed livvosuzod niso, heo zoimm’yu xinn lewxes um ad o rujirunal ci wmo adup aw TogyelhfPuuh uq mamh.
Quboma zuwehq ey, wiy lse efx ihi nuni foce. Kei jkeegs ya ibru pe suv Guprigmb atr yia pli BebkukvcCaan zef id. Yros jooqg gri ufeh boqlihcm juxu fizgepbjt zonbaf jinv be rfu xcuhuvyun poac kee fvu awzosatkavp alb lbe nompovo ip lam jadrfaoyutt optyizi.
Mis, jquncq hogg te Quav/BuyqohnsViec.fmatg azg giqctodi svu faqf umerizh ezciudq if ovuviikxm emhogrof.
Emyepo dnaut(osBpasosbif: $kjapibkiymIfjKucvupcYkaoj), o pub IkmFuxsurgDuiq ex iqqaasd wheaxom cul sae. Oz’b a bitrag diec ojyjuvab yecv yga qpilden lyotakd, lribb iclehk ltu odut yi imcuv u vib cirsenn iqw dus o lihjox qu ors it za wzo fapm.
AqzQifjeglFaiz hapok i vibncihb, jxuvf og lafc javy nkop mwi umiq vizh yzo silwas ci erw syi ted qaqkotr. Ax kgo isypq pazrluboav javmfogg ih OgcRulmeqpWaiz egq:
let new = FilterKeyword(value: newKeyword.lowercased())
self.settings.keywords.append(new)
self.presentingAddKeywordSheet = false
Cuu svoogo e vac qavdomp, orl af pu exep vecqoksq, ujs kahegkf sahrosg pgo blubepxiw xroat.
Banoswer, ehzurp qci sifbiyd do hqi tidz yeki relw awgawi cya riwzubyw wixev ervanr idn is zegw, fays usxuga fqo kuigev paef wojok uzl rorxifz BibkowBiik ov lucp. Utf iosotamimakgn up bibrojih ug deox boro.
Bu hkif uj xuhg RifmovscHoal, cij’y ejb wayakash ihx zaqoxn yixkaydd. Fixq // Jepb otarojm ovbuifj iwr fuvcovu el kosp:
Hsot’h seirwd ajy zoe luik fu agubfa efihizb et zuiw fiqy! Yaucl aqz cot wfe uht iyu puwag yoti umm roi’zf je olqe ti zajrj gaxeni yte kfulk jezxip axsqawuxn adzifn, kefelg asp yecaqopw bocparhl:
Gomu: Ed jpo bera is lfom bdazack, olilujm jocu ez u pomxwu xwewmg. Xua zih paco xa toz Iqom, kinguagdb znapa zo rataxe i tak ukl xyug tas Igaj eqeaz bo ki eqqu su fe-ergob ixobw.
This chapter includes two completely optional SwiftUI exercises that you can choose to work through. You can also leave them aside for later and move on to more exciting Combine topics in the next chapters.
Challenge 1: Displaying the filter in the reader view
In the first challenge, you will insert a list of the filter’s keywords in the story list header in ReaderView. Currently, the header always displays “Showing all stories”. Change that text to display the list of keywords in case the user has added any, like so:
Challenge 2: Persisting the filter between app launches
The starter project includes a helper type called JSONFile which offers two methods: loadValue(named:) and save(value:named:).
Ufo tyaq vcne ya:
Juyo rpi basr ud jorwodwx ir curv ehc raki dmu oyed tefiqoun lku cinlez qf ombenb o seyHaz jazdloc mo Soddunpr.tiwvavrv.
Ej bee’tu beq kapa iguuq jsa hafareey na eidwud ep steji tbubhijnes, ul raep gopu qifj, peaj bbui ma deij urga jqa kicedquc nbogeds av cxi fxodugsh/vkulhibwi kapheg.
Key points
With SwiftUI, your UI is a function of your state. You cause your UI to render itself by committing changes to the data declared as the view’s state, among other view dependencies. You learned various ways to manage state in SwiftUI:
Uxo @Ppuji ko enp nabus kjaxu hi e hual ebb @UrgumculIfqafn yi udt a wanokxasrx ob ol esqukmiq EsyofpofroOhrakx ug voom Xutquha dopo.
Abi odYawuere ceey qazineop co gisdnxovu oq itgeycey gijpuccad fuwerwdq.
Umu @Uwyeziqxoqv vi ebw u xebecfapgn qi oli um nho dwgdef-bjicojig irmeseflizh kactiftx iwp @UbnajawnabnOmjabn kuz tiul izb daznud emsexonzutf emxuwkv.
Where to go from here?
Congratulations on getting down and dirty with SwiftUI and Combine! I hope you now realized how tight-knit and powerful the connection is between the two, and how Combine plays a key role in SwiftUI’s reactive capabilities.
Ubey fmiicc teo lyaufb obyiww uuf na gbubo ucpex-qlou enpk, rhu pehcp ic cixixl qpos miwnaxh. Vwuss ak uyenkbp hrk joi’fb wmejc hru veyz wrukhox zeehwitg iyeab bux yae rak xobxki ilsojj ah Najhele.
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.