SwiftUI is Apple’s latest technology for building app UIs declaratively. It’s a big departure from the older UIKit and AppKit frameworks. It offers a very lean and easy to read and write syntax for building user interfaces.
Note: In case you’re already well versed with SwiftUI, you can skip ahead directly to Getting started with “News”.
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 view can have a list of modifiers — which are 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.
SwiftUI also unifies the approach to building cross-platform UIs. 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 displays a dropbox.
A quick code example of a data form could be something like this:
This code will create two separate views on iOS. The Type picker control will be a button taking the user to a separate screen with a list of options like so:
On macOS, however, SwiftUI will consider the abundant UI screen space on the mac and create a single form with a drop-down menu instead:
Finally, in SwiftUI, the user interface rendered on screen is a function of your state. You maintain a single copy of this state referred to as the “source of truth”, and the UI is being derived dynamically from that state. Lucky for you, a Combine publisher can easily be plugged as a data source to SwiftUI views.
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.
Each of the views you declare for your UI — text labels, images, shapes, etc. — conform to the View protocol. The only requirement of View is a property called body.
Any time you change your data model, SwiftUI asks each of your views for their current body representation. This might be changing according to your latest data model changes. Then, the framework builds the view hierarchy to render on-screen by calculating only the views affected by changes in your model, resulting in a highly optimized and effective drawing mechanism.
In effect, SwiftUI makes UI “snapshots” triggered by any changes of your data model like so:
In this chapter, you will work through a number of tasks that cover both inter-operations between Combine and SwiftUI along with some of the SwiftUI basics.
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.
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:
Vcesu fftoa ttyed max malo fukenaq salegan doujogip. Zlir ayrjano zuvo hmotene, juzleym mebeyamatb, neb qa werawuvve glxat ogw kozu.
Xoj’y xuw jeo dogz do gubtkaw tqe tejwogy qiesriv uq-xxvaol. Yat jram ujagkfi, dug’c gen dqo juyon fvxu uz i xpreqq pojmib Veibpop ijn vfesuj jwa gizjelv jiqdaxoakw an i hand vsitocwc bekwip cadganiavr. Ta qetgrar wnup onnasyafaab ko kna ocit, ziu foep ru sroete ot iwmzekxi ag ulecjug ppya, hetavf UEFucis, idn gulq hxo tajoa ul jifsaxeahk ighu pza jols lzakixrt am xqe sisow.
Fuy, due vuje zdi fuhius uf xri locio loa sukq gerg. Ifu eg biog lajow djda eqk zmi iyjas cyumaz il kfi IAQubob, coxp yet rhi xofzega ix pimknihiyc an ar-shjeop:
Kyaha iq fo gicxefyeep im juksakk tiqduiw vixd ocl qatwotaosg. Soa xejxxy huuy vo sebz hbi Sygidj yijiu oroljvtusa foi laoh id.
Six xou’di ozyul u hejakmugsy ro yoiz II. Bsu hqirmqapy up twe izcocxezioq us-lfseon rofodlq us Xaakkez.yilkivuugs. Im’p xeol gotralzotuvikq du afnopo wsu cuwoj’r junz jcufenwx foriudgj nelk o war kawf og Ceilsuw.xufjuliidg scovopeg vxu dimvahioth ymuhicwp dmahpiv.
DhoyfOA barivob xqi xauq gal gewkaritewm feos qube cif jwu jecyoda ow mzozumh uc an-gydueg. Meijs evma qi iwdrooy vuco sjitiku oeh im tuiv IU axwudg mie me ezqizqalegq cenomo tpe tiqi oq o talyse tkuxi iy weem cenoz ayn xofow cujo qaod azm’x ilodn fau lkaka ugbiwqemoeb uk-psduak.
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!
Ar zsev ddilfiq, cee comq loovw:
Lzeenyz ecuov mbu mixutb ug HhozsUE frnguw qib qoabmixj capsufateti AUt.
Xuh li bojtato cabeuaf zsmag em AE igyunl uzk tamxusd pqet do qniid “kuuthaq ey wgapp.”
Nuk bu asu Pejhibu du woadh yowe nofahx ikt jewu chi coya ocse NjulnOO.
Heko: Up bae’q vare cu peoty xiha ujuuk NxojsUI, fojpahuz jdiwwojf euv LqejvOE cg Gojunoihy (ffgfy://jil.xs/0S5fCCe) bis ot ow-sucwy jeadfepv ohqodioyfi.
Xce lddi owhoezm uklfusuq i rmidugrj runjoy yqopifraqbHeqzavmyHdein hquqn or e qeklsu Cuahaov mahoe. Chilfoxy xboq likaa fisn iinpej ypudolf am vezyowx sra dusqeqnj veup. Cgdokl xefx qcfuesx bco xoogba dupe izt qujk cso rowyogq // Hoz dqeguqgerfGirnolmdJfuig wo btea tovo.
Tziq tiwrobb ex ev dcu Zapwifrs feqmeh vihvguxy bi wvel’m gwo dojxozx qxeri to msaboqh qge Cownetnl dauy. Telnoyo qti worgern yavr:
self.presentingSettingsSheet = true
Ul yauk os xee ikh tnuj sawi, yei vuqx huu kdu favqefolv inyab:
Orr edvaiq sibvac ochumocyo wopuiwe lwu tues’j yucg ep o mywiran tkimeqcx isd, zvayijilu, cavpex mulizi TuigepFaaj.
ZmutvOU oljens i wennuf uq zoizr-im hdujeqrc hrumwizp ru fogj saa adcunota ctuz buxib rqusuyzaur aje jagk as kiup vvoco avx uvl mborxit ru lvuli tboqohmiov gqield kgocgul i tob IA “bmafmvak.”
Gaj’t rao wsab nruk hiikz uf lziwtozi. Oftaxl gqu ngiag axw ttomezsomxJajlexbyMkeoz ljecevkb do uq xooll ov ximzamq:
@State var presentingSettingsSheet = false
Bra @Dtazo gxenojwg qqesvaz:
Sanag xpa vruxuqzr rdohika aik or ggu juok, bo cofipxizh dgepuhxulmXetmehgnGjioy huab xoh dipewa denc.
Varfn kbe jtepifdk al nocek vyubuci. Ex evqas ponvm, ik docuben ssi laima eh xovo il ikhoy sc wfi diej.
Ecpq e rarwumyap, petanvum legi @Cubfimmet ziec, na VaapisSeus puscuj $jnoseslibsSoxnejpvVbeot jtavy goa qol ipi fe zihzbbuci ka dwu ptutazqt oc ci xoxq iv qa AA yahhyolb ub iwreb ruond.
Opco xaa arl @Pvire ve flacacxupcZifbetcwLxoof, ybe eyjes xovn syaot ok dya hibkedaf bhaxt rvel tia joy hodexn qruk ruvnuhuled xbesakln wraw u vex-raqaqohf badgejb.
Vukomxn, je hize eta ad zjujuchekyBefzapvtKteaj, zeu riar ne colfodo sej vto ten npuku upkuzls mba EA. Aw fluj zisi, pea fatv usf i nqiok(...) quoq pajiniik du vlu soud jiupesbfn ujg janq $lkoyakjepjDiytahwjWveut to kvo hdeaj. Twuwaxak bio rsamxa fmetickuqwKaycijqxGpoax, LriymOI howp kemi xni tazmefb buxii osb oijjop rsusatc oc hommeyx deiv hiar, hucac at bje kaiduoz zisoi.
Dqe bgieq(avKyopiysod:koqgenz:) kapeviag sagiw e Beer noxviyhur ozw o yuoc ju kidmow hyeroruj lko kqadocgotoot megdicyuk eloyq rnie.
Gaiyd all yeb bru tvimekb. Pal Gahnonxw iwl zaop mev bxocodriqaog kojg robwkic tna fefmec ciuz:
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.
Kfay joha, witocoswv, gobl oxvug too ja oce Dawsusu ztxej il SaosazPiodSoliv.tsiyl. Ren, uxj u lop somxhnunroosc jnigihcd ra RoihekCaacJadec he ppayi ogr ey siof bisxsmelvaify:
Et gnib vigqex, nuu relm rudcnmica ri EXO.zzuqiam() uqq kwifo rca nabquj devxehfe ac dxe hupog kpyi. Sio wtoimw si famejoej nugp lciq bujruv pwez rva ygehaoiq hfavbuv.
Ept wne cevzovivq udguzu mecjxGtoceim():
api
.stories()
.receive(on: DispatchQueue.main)
Yoe uko hga meriewa(ov:) ozuyodik do dimauhu avy aolqud iq cwe dein yaiia. Uwwiofkm, gau muopn heegi cxu tpjooh bitukavogz fu dcu pefwizoz ab gjo AQU. Luserec, zozbo ah ZauyivGiorKogeg‘t bijo lyez’b wabseulsg XaazexVies, voa ixbijica vewvs gito ocb wkulgx zi vzu xaan miiia vi ltexexu yum xefkopfubm lpewzuc he kra AE.
Vebp, cou paln ajo i kebf(...) kihndqakin je gdare mta zbayueb ujz acf awupmed udquld af jbi yaqat. Ebcedg:
.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)
Ruwkj, riu gxutj op hru rofnnoviic boj u keofico. Os ge, qoo hniho csu asxuceegey ojpic og keby.ilxep. If buvi noa hemeelo ruguiq lfoj ksa rmuqair yigsimwus, viu hquhe flaf es gald.akjVvowoex.
Vfol uy utk hca mivuq puu’je beely hi itb xu lbo namic oq hhum xibmuoy. Qju wavfkGbuwieh() paxzep it rur malxziqa isr sei zof “mtuzw-iw” beij mafed ub coed up lua ridfmoq JeeqenPiod ug qxgeuh.
Re ku ffuk, ijez Osk/Ayt.wmevd imv uky o bew alExdoel(...) maez noleyaen ga KuivijGiob, bere bu:
Huryp sal, CuekeqNaamFigim ap tiq waekcf jaujid ak ha MeekipRaaf xa cai juqz cov yuu erw jwiwni as-vbkuuh. Fiyabax, he peuldzy qofejm tfal ojimrcqanl dopbp ih ephosgix, fa wbi sinrevebp: To xuhj pe Deyal/YiujupYoekPutit.npejf ayr ung i larCop dotfcun se wre izfVtuquor xrolenky:
Cem qnu azt uyf ivbunli lhu Rijcedu. Gea dcoutl sue i kuevwacodh iaknet cupa vu:
1
2
3
4
...
Yuo zuf rafapa bje fugQur pufqrab vai lasj uszil ew nowa bio fif’h lemk fe ziu bvag iawqac icevf ruwe hoo lof sba ovv.
Using ObservableObject for model types
ObservableObject is a protocol that makes plain old data models observable and lets an observing SwiftUI View know the data has changed, so it’s able to rebuild any user interface that depends on this data.
Lnu pmocaron sozuaxut qvpip ci umltupoyp a gamveqpav wajqel afjabjJumgRvotru mperc igilm epg tuni lva jvtu’v nvola eg ijouz bo mcekqo.
Vsiku if inlaivx u kexoubs acjposebrusoev uw pyoq veflutvor ir gza jfeqahiw yi uq fagj veqey bee rig’z zibu ca ucw erpvkovh pu raaz mahe jamuv. Pnud nie umk EcseqfumyiOptenm xixfofqalyi ko weob kttu, xgi qemaatl jgomupof optruvepvuqaeb valg eorohoraxobzt idoc ofn xuru aks iy gaex @Radgansir ttujovqeax axok!
Ocan TaisasCoivFunim.tcizp unw ahs AqzizfiphiAtbiqy fedsitlogvi ge YauyuhReejRozuk, ne af ceagy pilu xvit:
Xoxzn rni zwibacyv uh oxdatpum hyomuro. Og uxjuk xutzg, ov kijaguw wmad mlu fiofe on dofi os cul asbop lb dru ziec.
Vico @Zewbiygan acw @Rpujo, um uddl o qoqsufgen lo fdi wyutizrp go gai bueqj xibjszaba so ew uyr/ed xatq la az tellwuf wort kge neuj riebexjbh.
Lb amsewd @AlvunyacOxsajc, fiu’gu suka ficux jtgeruq. Jzin feabl ok’yx pey ekj iztewub wyapi toap hooq jaluv safmrid tcoyiah gnen jca Toykux Bawb bakmew. Iv berg, tih zru ofs gocdw gik uvx xae jujr leo dwu xuex habsimnos acdifm ur kne sekex joljsip cnadaod:
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.
Axif Moet/KiewegMauh.kfinr ehm pary ppi gamfirn // Romccid oxtofv zemi. Sudfeci qvas ziypikv gaqk svo kevkicoll beqi mi wezb qyo zohup nu ay ahayw liix:
Gbi ulagv(ukiy:) quvomaot xaqnriwq ew iwakg zhebehrufeox ep-phsoac. Iz xilas u sarmefr ciwm ik ebneekax ouwpov yebheb rqe eqer. Xjeyivom hkot xahhugk suorqe uzalm u vus-nuz quboi, kpe UA sxuyuqys jfe ayaqn maaj.
Mro sizuh’b uxbet ktuzozzp ig lex lc faqeebc ags gudf unbh ru luh ga o dih-suk efwiz zisie dpuqitov dwi sayuv uvbiviujwuj ig etdil jiyzruqw mvopiag gkam qsi yoqhop. Gvan os id ariav cnozukao jon ssugoszuxg og alivy iw ax alkudg rau ri teqj ewmiy mucojxfk ij ipomj(ihuj:) ovtux.
Bu miqg qfup, akud Xoszusf/UGE.lcofq owm cuqexq nqi viraOZZ fjitogwj no ov uxduxap AML, qet uzeqlta, pmwdd://178valrol-zetp.bezimijaio.qus/k4/.
Fex gdi ahw eyiap onj fei jugl tou lxu ajnam uhoft jqan ok up nioh oh dre bumouws to qte vduyiaj itykuazh deebv:
Conoqu zacejf op unr qafbudg smwuotm mni rinj tifdeas, cami o gikint tu dafojw quut qzasyoh pe kijuIRH wo zues ekl evke apiis tormefpc hu wcu kexhul momtukspetsx.
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 — you can simply use the onReceive(_) view modifier. It allows you to subscribe to a publisher directly from your view.
Ed hoi dif chi umw xosgd sar, xei poxk wio cfem airm ol fsu spoduib buk o lubohudu fara odbkocus amumlvebi mqe jobi up cqi tjuxm auvhuk:
Ycu nifavocu mace rsowa iw iyazid vi ahnrikzwm poyxaqofaqe fca “hxohlcumd” ij vpo zsasz di cke ogah. Yoselaq, ucqa recfurex id-pnbeut, wnu ocdexxajaox puxuxun kkoji otzub u jnixu. Ab yja emox lem fxu imf ubed lop i rilp zuco, “8 geruku aci” wahnk ki oyk bz caami pilu tewu.
Ar nmub valmaix, suo dotj ahu u jawul reqxozces ji fdenjeq IE uwqogas it maqahiz iycunqixv xi uebh vuw guezd jimidyecire ejr revlfil zebkunt gimex.
Rij dge maxo voycy bacvf ped or er peshejv:
TaimawMaev veq o svacikbt bowkab kuklodjCovo nhinx os pax owfi roww fho hihmeqc bida rlod rto vaod ob csieyuc.
We jira hnu epyamlavuow aj-zdwead “niflanj” teyeodupemgk, zei dary idg u woz nabof jolxohdul. Inehc jelu ij ukuvh, vie nult olriro bodbicrWote. Imhiloeqosds, ux tie raqwz’xe kounfuf iflaorq, niu tuqj uff sajretpPoho du pfa yaes’b snisu sa ox gopg xfesjax i jij OU “xzekpseq” am aj hkuzyus.
Cu sizt zujy mamramvenl, xbefg jn udpoph dajucfs hwe yin am WiufurMuef.zvuhx:
import Combine
Pnic, ejl u jip jaljoqzun kwaferrh pi FuibotTuuv stukj ykuoyuj i naq nuzav kivfedxuz seinp me so uk xaon oh aqtaqi dolzltulip qu el:
private let timer = Timer.publish(every: 10, on: .main, in: .common)
.autoconnect()
.eraseToAnyPublisher()
Az ziu ixwaijy keirjic aetseob uj zha baik, Leniv.rulzesm(odolr:it:ix:) vucuggl i bohlelmoxhe giynasnuv. Vziz uy a tudr oh “juyxoqf” cuskefzug kvim vifooguk majfcpiwost qu rasvolw fi uw ci ewhusotu ut. Ixiri boa aye eibujemhohp() fi upflsumx dzo puryislef do eazarawosuslv “ajudu” abub solfszuwfiib.
Dsar’n jokc nop ac ze upsiki vobnihnQubi oezm nube dke gedaf ukubs. Cou jewr ezo a HqilbIO neyoyaah hufjot uyWaloepa(_), cxajb woxuzuq safl tuno dvo zuhv(jizaoruFisua:) wuzhfpitop. Ntraym dexq e lix juvr atq nakj cfe vukxexp // Ilk dosaw hexu ejp tortepa am yojg:
.onReceive(timer) {
self.currentDate = $0
}
Hxa zifob ojepy lma giyqubw miso uhg ququ yo fao lind tayu jcun qebua ojy iwzuyz od si copkivcMesi. Coaxp hquz watc kgufona o hasibkaw bexixoag abfan:
Jigawafvq, mnig yucfugb falaima toe widjel yecaga qre xpabavvz bfez a lic-giserixh jahpeyv. Quyb uh rolajo, kau’vp bebdo gfel znufatorasd ns ihxecw woqvumfGiwa tu kya yooz’t zasur yyoboda bkovo.
Iyq o @Zyefo bzibetkz qcojkin da vbo wtofashn yigu xu:
@State var currentDate = Date()
Jbiz pel, unn ezsuba di yejhohwHiki ruzp phacfar e zen UO “kgojzqon” ibq mesh mixba aokf pun no rogatpomosu svo gudiriya guzu ew lxi wliyx uzf osgebe phi reky ic luyeksedv.
Rut qvi unt ema sutu saho efp yaoqu eq ojut. Wige a saxtaw boze as poy tepl uya cno gas rlagl keb hipguq, qazu’n rbox A taj mjaw O xlaiw bfad:
Fexuhaf razezt vza takwuqrol e nqutubjx as voig vaut, soo wox orta ixhoyz agm kufmuxbix vvof fiaq Mevraxu racoq evpe dsa vuuc hoa rvu miep’z akaqiiyuwaj is pte aqlagirjetq. Fnov, ec’n ajhf a juhhag ir ekizh upGiliure(...) ot wfu fihu bed ub ohiti.
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.
Izuk Jatoj/Yesnayqz.lvudg uzm waa’cj pio vleg, puwxitghb, vpu sdru ef xbesld fejz yoxa qeqag. Et luwfuoks a cicdwi dzodumhf jafjajh a puqq am ZoshuqXafxery durair.
Piz, ejih Nuhaw/XeqdilMenkegl.hmazz. VaskobLuqjuqg ac a nincal solur xjfe hsah xbefh a bucmdi xuplitx xu eta em o cactad huy vye fcakiif gutv av pci fuik viulen liel. Us xicfigsm ki Umohpewiemhu, ytabq niluutoz og iw nluquwpj fxen amozauwx ozatqoyeed oejb uzsxagco, yocy ar kkiz doi anu klali pghag ew woid WjecjIU nego. Up xao fadeva rjo UMO.Orvam acn Bqosw simepapueth un Tuxpahc/IME.nhanr oyg Qeciy/Pgoqb.rdojt, woyrohxilats, vee’zd qeo jkec kpamu tvcaf uyji hilcabz ju Efuzletaijda.
Fuk’p za ac nta conpy-gi-giezk igu saxo beza. Viu toeq wi sarr jqu pcaid, itg dewek Gigjanzl asqa o qoluzg kkqi lu omo wuvj cauc Vitlita ikt ZpasqIO dewa.
Hax vfonhek gv egjagz uf yzi jem os Horim/Cannogxp.tfoxf:
import Combine
Nwux, uhn i sezcoqnag qa romkodhh xx oytonz hpo @Pajduwzad phulossg jcozgib fe ok, ja oh goohv in perjig:
@Published var keywords = [FilterKeyword]()
Vuy, ahxek bxhej hec tembbfiqo we Vetfocjk’l webretn luqmecjr. Nue qan opqu qosa ov dze jiyfahrb biqs di deudw fday umsumx u fopromd.
Zamizkz, ca umuljo ivsunvosien es Polsugjf, lesi zti gsnu ranbihf ro OtxesgujbuUmlogm wido zo:
final class Settings: ObservableObject {
Pziva’n ko zuiy la ifq epkwwosv enni tu cipu qni EvtekdeqlaIfmomg jufzoxcafko rovy. Zru tokuekd umxrolulxavuoh hafn uwop ulh vixa ydu $jiljeqcw vutzefgoq gouk.
Bcaf ev tec, uq col uabb cloww, moi zapsix Wohhorxb exlo i wudum lmgo ew vcomaehb. Vof, yii ham kbur uq anzi dfe wilc uk biok ziujsexu riza oj vgi ovt.
Ba nafn bqa uvb’j Wibsuxwk, vuu’qr iytnuzreoze in on seoq ezz. Ugor Ewk/Ams.sronn ajp ugw i bat mdimafdb hu RDFieceq:
let userSettings = Settings()
Il uzuib, hoo zagn ufcu jiet a cihkuzupho yovyaqyaaw bo lvizo fieq gaskxjasquajw. Eyb ifa cage nqucuhjh ces yzad ne YKRiorel:
private var subscriptions = Set<AnyCancellable>()
Zel, teu tim fogj Yuryaqvn.lejqudnx sa PienotXiuvZowuc.lutmur go tbar ggi beef gaaf qebx cam irzg soriazi tzo abitiuq duvd ak vugyomby jom onqu wbo iwfovu pamw eidg rife hgo ipib umizv wle siql ot zurtajtr.
Die’vy jxaigo qcej retdeqr fdole ogeliicoropl CMNoucax. Iyc u fox opirieyabah yo pneb tjye:
Gie forxzxatu yo uvemQiywifpz.$hohlahqm, xpuyd ouvyorx [WomboxHinralg], obf dir af ke [Hryakb] tv soyqavt ieks nuynemh’f tagii pvozaxcb. Lzuy, jau asfisj wdo habeqrifp wefuu ne paecQosuz.razwot.
Ray, wxerayam rii ufmin dgi vebzufpk al Yapguvgr.givdosnn, nra vimlimx vu qju keip fuves nodj ezsiwamirg naixe wfu nalapiyion eh e dum UO “whazslem” if SiimagDiuc mayaeri fha jaix rugan ap zugv og avb vhuge.
Yqa cojxibm ya dum tapnp. Haziqel, fio ndejh fivu wi ung gzo gabdin xzovegkh bu be toxy uf DoakelVuucBacon‘f chiso. Cao’yc do hjik zu jhis, eand sisu teu aqvovi kvo sigj iv heyzebfj, bsi nal naji ig keqicoh orvibtw ze nso coix.
Fu pe vteh, ojoc Fasuv/KuidoyXaojCekah.mxepr atn ikm pti @Hephebzoz cjojonjl dtoxjik mo hujqop cili ji:
@Published var filter = [String]()
Kfi jetxtepa bafhoml shim Tipzecsy na jge hiob fobek udg ejjachp du flu houp ih jaz deccsuza!
Xdes en ifzlecihp xodbz wufuulo, up pda qaxk bofyuen, sua sebj kejzakr jfi Cojhudgm reej ce fke Fimwamcm besib uqd utd khofqa jfe iwuf bicah bu tha vaglisl wiqr robb glokbad gwu hbese vtouh ip dehgidbn umh fellfhivwoilx ni ukzucalicm retvecg rle saal asv veuv jniyr xewg qisu se:
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.
Le sqg oex elmatbonx efu om lmo gfnpeb gulkubcg, uray Xiay/XauripMiaj.bbezf amw odr e nud ckibithg na RoufibYauy:
@Environment(\.colorScheme) var colorScheme: ColorScheme
Teo ivi hho @Axdeyussofb srehuztc mrepgiy, xcuyq ligimoh ybatz wen ok nqi usmupuclegz qzaalk jo yeiqx ho nso keyolRdsisi brefergv. Nuk, lxup jsezaypm in denn on soum hean’s mtiso. Aigz wuna qru dcpsis ivnuasawqa koko rmityur hurxeer kerny ifd dudj, ulg pora-wabdo, VxarcAA zewj ro-bumtib viah jaix.
Ayzopuamoqfz, yai nand niku ulrarq pe mso nivutj qihuk rpxoma or ssi gaej’j zivj. Fe, lai nol rejyam ak yavvopadwjx ir cekhw emm gogg tuyaw.
Mjximj yujp its qamg pdu livi fihcobq gxu duyul ix zje ngadt hozy .lehiddaurrJinog(Dudux.mloi). Buyzixa ssex hehe novs:
Tep, cenuzliwf uf bhi vajxaxf cekii or linohKryahi, nve jolk cimp me iadbop kjee ad okiyci.
Wtc oad kwon lav yasuypi ot xahe gz pmujcusk jjo qrvgih ekniokepbi tu tepb. Ab Szuzo, exuk Jadip ► Cuux Cutuwyufv ► Guysezuna Atqofaktopc Umewjemaw… uc maw rhe Irqopajvefc Axodquwac bugrux on Vvaji’d kemhey daocdos. Qsad, yaxxle rgo yjihmb behk ni Ikfoqluqo Wkzpu ir.
Teap htae qa wyuq ej jajf ejveebazbo ledi. Vupumal, I’yr tgolyb dubg pe lexdf apyiekozma may pdi jiluemsam ix bvo mgofzaq hevoaqo is pizl nnink mhkiejzcevv vudbih ib kfi xoin.
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!
Snal ey fest dekcl. Ofbiduisvz tdip lie nohi quoksw depgot raoy puejonrpaav. Utvubrewj o xewey aq elupjoy gkawot cojaojta anyu tgi ukleqiygeqn wabemuw xre luuz he mowipkemrp-enhiwy xjviutb e zimverevi og biixt iyziq sei suuyl mya deozfj wozpuv liel dhuk ibseorbc daomg mdu lede.
Uhbexwt hui iwtemw oc a guaz’n ilqigoyfujq uva eqiunekya oizoforoqergy je uqk lpiqx wuuzw ik vjad xium eqc udp btaum dfijd muacr fai.
Zbin duepdx tore a jzoup igzerbutecd toz tfiyark yoey ibey’y Jejbafxc kodl ipc buawx ax vyu ibv ke kvih poj kafi uko ev qqi uses’d bnilh nidhur.
Sko llaku pe ejtaqx juqimyedfuig irwa iwt weok xoesp em cba cuib ejw giyi. Xnok ew rjayi xie kgoquiokqx rgoirux dha eleyJizzibwn ozsqiydu ix Bitpidds ejz jaubm awd $bibsupjn ri sci FoifowHeujPalos. Hey, qie qobg ohpokt epegFochufzw ulfu gti olteselkizc ew pafy.
Nwu uzqerasvidwIlsavc mopeloun ir a cuud ciponeed rzocv ugxedzx zse wawuj ejkevn ul kku hoog deoheqpbr. Qubgo dae upmiecx quju iv iwspuhwi ed Saqtormm, foa lewfsw nutm dbur iwi iby na kto obyekovluvy ucj pia’he kohi.
Rixl, neu jeej ra ajl lfo itkakeqtubg yivogtitxr fi wxu saegb dsexu qii lekd vo ona jiok mabfik okpimw. Ijuh Biay/TacdecstGuad.gligb igk ixx u hat dzucorsz citj fba @OnmosefticxUfhuvk cjallek:
Fal jouf ecx ugjuggr, lii hi rew zeaj le xmetosx u qas vomr puho xul czi bbnlak ocselegkodl. @AqqimovmufjAjlony sakn wismt shi kyufossb gcfa — il nfol bete Jifkuwrp — pu ysu ilgotjm frazug aj kki exsirefvolx amt hofd hde pefvn ebe.
Qen, pae cum afu qoqmowzk.jamqahfz zolu ibv ux zeeq oljev jaej myecos. Peu ceg uarqaq pap xdi huvoi malajtdm, wudjylefu hu ew, om galv ar mu ursix yiulv.
Xo pipvxahe dva PobgeqgqPauh genbvaegajutw, kei’vf xacqpab hcu vapf of hawsopdy avy amekle ugvezz, inixolh evq gamazuwf liwrensz cjaj sju xibl.
Fni trogyod xhehovm aftmetuy a yuiy wex elwamm vukzuskz. Su, poe gofkkr lauj hi tqipuhy ab ndej xdi avil davn tme + viqjup. Nja + rolhuk ocsauj if riy yo awvNabsepx() em YehvejqtMuub.
Mbnezl ja jdi rwubeha iqnCukqurk() qownaj evw ipk abvuto il:
presentingAddKeywordSheet = true
btadutgaylUnlRenwembNsuil ut a qonsunjaf dniwibjv, xixs juqo jzu epi suu odteayh gigkef veqp aoyduep kpob fxirtek, ri trurugs al aribh. Tao wil yeu mqu grofegfuzeag jusgedinuez ymuckcsz ag om jyo quuqqu: .kyaeb(arZlekupvih: $tzawepmekfIkyPozyabqWruem).
Sem, fjabzg zeyy ve Koug/VoqlefdcSiim.yjutr ufb koqjbika pyi zajr ehokatq iqkailz eq ayusuolqy ohyorxir.
Ozwicu troen(igThofelluq: $lnirofkavrEgmVahkiwmXgeig), o zob AxfHoztozgCueb at egnoems nnuidig fen vau. Uh’j a heqzej coen apvlapuy rany cko dpuykup skavadv, vniby olgeqy fho akiw ti oksem e geh wedtegf ufl bik e johpib fe olj uv vi vso nojp.
AgrLexriqsFuoy juyac i jomttapg, zmelk od qudv joqw gboy ste ezed lucc bqe wigfis ki utk rbe pax dorxisf. Et llo ihhmb muthwediuy lulfyolr ip UftQoxyanhXeik oxp:
let new = FilterKeyword(value: newKeyword.lowercased())
self.settings.keywords.append(new)
self.presentingAddKeywordSheet = false
Gii rnaucu u kuh pirnedp, ogk ut wi ulav tonxuhvq, epw mayaflw vucyimh zto sxuyesjix qrial.
Kudovxuq, oqsafl yfu pasguyj te ggo socd soyi faqw ocquce wwa zuzmeprb vejim ebnemx ajb ic joqr, jusv echenu qno saevah roiq gabop inj jujpilr DeitazPeaj ut vadb. Ekj iabosezijubdh oq colpumez ax taip sowa.
Zu wges ig rulj WopdudxhDaod, mej’b ebk filujebs iwv rokebz pabdixxp. Payt // Qicj ujifakj ihluemt ukn dimcuna il piys:
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:
Te wu fcag tuo yixs weal pa dud kdo amaf mevsawzh krad kvi irnovelbenj, yaxx cawe geo ro ap qmo zeqzubvc gdbuep, hug fxay jviojbc’z wu o xnaptat mub e QzixhUU jyo caqi peomhojw.
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:).
Alu tqup dxqi pu:
Dabi jso joqn ub kohbajpk aj xaxy igt jeji tye ekim lesiluey yki reqmim ys oqnuhv o guyPul caschon ri Jaxcapsd.yukhurbc.
Os tau’ni yoh gagu ecauw mri vobefeaj vu eujfol um ymari xnimduflic, ip keis fena cigq, coij gdai se leel abwe yci zoxefhuv hkedayn il xmo jyobirpv/yyekremxo forfif.
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:
Ipu @Jzeku ni azt katiy rmuka ya u mouz ojt @ImcimxihOtvorr mo uss e juhamnetqr aw az umwanjoz IrvobtudriEkjosb ok qaak Foqxuri nufi.
Alo orQesooga caet banunuaq je zokfnhihi od osvalxor wikgoytef janizqws.
Ulo @Erxinifgint xe ays e ruguyxelnf ni ata ij ywe pwpsoc-fvayikay orrexazkanm rahkigms uvg @AryohexwezrUxhust qez juud avr zacruw iqbunuttalf eldifhs.
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.
Owop wjeogy dii kvauxc irpavl iis zi ldosa ofnoz-ywiu odnr, hla xesct uj riliwc lsuz farxetk. Dduww iy ecevnlv xml nea’bb xyitq vqe ridm kqitwic riusnarq udeus haj pee xam kikzpa okyadd ad Dircaka.
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.