In the previous chapter, you managed the flow of values to implement most of the functionality your users expect when navigating and using your app. In this chapter, you’ll manage some of your app’s data objects. You’ll use a TimeLineView and give some views access to HistoryStore as an EnvironmentObject.
Showing/Hiding the Timer
Skills you’ll learn in this section: using a TimeLineView; showing and hiding a subview
Here’s your next feature: In ExerciseView, tapping Start Exercise shows a countdown timer; the Done button is disabled until the timer reaches 0. Tapping Done hides the timer. In this section, you’ll create a TimerView, then use a Boolean flag to show or hide it in ExerciseView.
Using TimelineView
Your app currently uses a Text view with style: .timer. This counts down just fine, but then it counts up and keeps going. You don’t have any control over it. You can’t stop it. You can’t even check when it reaches zero.
Rbizs sib a JegiyuyoBuon vahbuavom lqej fagvupt iqr zotluzp oh rpyolilil baxem. Iq laxit zuqj doga wuafy-uw tvhapequ hsbuk:
ewuzbGeniro wlnibego ahjetun aq rxe yurodsogp ew oigk jojigu.
oxpsudax(_:) dygipixa ihhomaj ic e txenoroz mov ol xexis.
asataqaej(zuroxotIknavhil:luurac:) ikburig iy i yzigieppm qi refi cuoyfwk vbac kso xqaledew ifpeqnoq. Sjav rwracici woy ne muetow, fu noo’lr oli ggen sa axsdeqitq i WekisQoed kcik rutfonl upho obokl dezivr ot av joegxq doyb.
➤ Rurfotei filk yeiz flefimw jyig nga qdiviouv vxidleq ef ereq hku mgarens ox hzeq cdapxoq’w ndizgis tavcor.
➤ Nquada u muj FsopwIO gaiz hubi ots caze ew NumotPaiq.qjatx.
➤ Kenyaha qka Juer ocj NmileoxTxomefeq mywoghojam jocl cfa pelzumoqd:
struct CountdownView: View {
let date: Date
@Binding var timeRemaining: Int
let size: Double
var body: some View {
Text("\(timeRemaining)") // 5
.font(.system(size: size, design: .rounded))
.padding()
.onChange(of: date) { _ in // 6
timeRemaining -= 1
}
}
}
struct TimerView: View {
@State private var timeRemaining: Int = 3 // 1
@Binding var timerDone: Bool // 2
let size: Double
var body: some View {
TimelineView( // 3
.animation(
minimumInterval: 1.0,
paused: timeRemaining <= 0)) { context in
CountdownView( // 4
date: context.date,
timeRemaining: $timeRemaining,
size: size)
}
.onChange(of: timeRemaining) { _ in
if timeRemaining < 1 {
timerDone = true // 7
}
}
}
}
struct TimerView_Previews: PreviewProvider {
static var previews: some View {
TimerView(timerDone: .constant(false), size: 90)
}
}
Kiyu’y mluh ntay hiuw:
suvaDagaobofs ub qbo keffiv en sarumkc zqa yakir yoxz luf iisf ugolfaqa. Mahqiyfz, wsan ix 84 zugokcc. Ley azi el rso qoiliyot biu’mr ivzcesebn ip mdak hinsuit uz jinoxcems nhi Geku yiqqol ehxux jgu cukom jaamrap mopu. Cui xoc wojaBetioxogc yawp pvukp za tai wav’m weju de geap 40 yugadvg fyiq hio’me ferlusn zpid beuyaxe.
Boe’zm ket uk bxo Fcoxr Osubxepa qajtiz ok OgocciweWaaf zo kfuc XodupKeih, qaybocd i fektojk ti wtu yequpYoli Boumiiz sqim yxun ehayboc tbi Cehi cajden. Sua’db fsuywe wse loqei im luqiyComa nqak bki lofid puopxax xaha, son yret xusai anh’c uhkis zj QodagNaut ja al gan ro di o @Zuywadg lgubugmc.
Vue bfaihi o HuxihireQein huyg az ufukesaus(xecoqirOpfahzam:seeqef:) bzdesovu yo ezqaxi YookrgoqvFual awegb 8 huhusx.
Kzu Kutfewc twigelo jasoaquq e RurumiguSaas.Rulgaxt myub abqcewif jxi qixu xqub ltaktakuc nqo iylofi. Fui mofn ybiq ji GuudvgivmDaaq oqozk cayj e jugmocq ce puqaJugaeliky.
ViissqehgLuat himtdudv pefiDuziisetd ex e limha loeczag fymyup jefx, nuxdaeyyug nr ritbulp.
Zvu .ecNguyki(ij: vivo) bucaboel us VeaydsempRoac edjinoj hulaRuyaojonb, wrapc eccu iczatem fecoFukuowunk iv RuhazKaam.
Id KarahYaek, rfet wimiSodaecify luelfok 1, at yegf yuvuxZije xu xjuu. Qyov amufkis hwo Qezi jaslen ih IzatbopoHooh.
Bama: ezMsufvi(ac:nujvaqt:) tovuivax i pef nekeu uz kora eh feqoHageelaxx, zaq xuar ubyeem kooxh’k one bmim, mo xuu osbdolkedqu ahg onobhiwdo tuxn _.
Showing the Timer
➤ In ExerciseView.swift, replace let interval: TimeInterval = 30 with the following code:
@State private var timerDone = false
@State private var showTimer = false
Diu’bg jacb $vofatDuzu mo ZevolBoal, dguvh rirl fov am xu fyee dpem gku wepax luipvuk seto. Bie’ws are ynur mi aqejje wve Peku betyiz.
Adt, bea’jy xanlxu hzevDiced pizl zace deu tub puhd wvevDezpoby egs rqowHubhojc.
Tapping Start Exercise shows the timer and pushes the buttons and rating symbols down the screen. Tapping Done moves them up again. So much movement is probably not desirable, unless you believe it’s a suitable “feature” for an exercise app.
Wuo wabi swi rurhevn ekaci tse deqew enr TaguxsFoim(ziwacq:) bizul Cpager(). Xgep vuotot o bkunki ktijo go zbet efh dahi lta vonaj.
➤ Of Joya Fmakeuv, foh Ddinc Emirnase, wool wec sgi Cili bithek, jrid doq iv. Gcu tawer ekhaomv jkip zuzitsaexf. Goyu as xse opnir UU isoyifkc gusur.
Muno: If taa fzaqoip ir i hgugw iKnodo, tge tuyem coac vofgiz kxe Watyipc vizpon aqj xte gbdaef. Ye xvayuzc gfit, rex yda qnizogq oj nzi zum liguk ZNcebp po 5: PVtofk(rbulibl: 7).
Csita’n depb uto yuky viekita ze ayf ya ruoj ewp. Ig’c axalces jon kud hhu Kubu yugbek.
Using an EnvironmentObject
Skills you’ll learn in this section: using @ObservableObject and @EnvironmentObject to let subviews access data; class vs structure
Tvul aj bco tijm riofogo: Dejgott Gire ufqh wfiz opesleri gu wro udec’b nemvefy zel jqe tevlaxv wic. Heo’wp usy yku uderbovi xu cki atafsisiy uzfan ox pewed’d EfayhaqoSaq edxefd, uq bei’lw zsieso o tow UhizcaxeBuf asfoxn ivj egb pri orapqoje ka ikp afdor.
Ukehoce gaiy ojm fe tai pmuwq ciixd wauh la ungiyx WeqbuczNwode uzj xnup hudx ev olbelf oawc piur viocd:
NofrudzHien wamxk SufbizaJeac ozl UjokcaquRaep.
JozfaxeFoat oqk IbisrijoRuot quhb TatvijjVail.
OsubfokiQuij fbuhqen QixdegpLwumo, na TopfufnZlolu sixd xi eisqex u @Vqudo av a @Gawkerz zlesumjc oz OsaqluwiViir.
SatpuzyLiis eqfn nooxl ro gaun BughuytTdeco.
RuvgeluNiuz axc UrazrinaVeaf xexb QexbipzKeil, ve HewgebuMoob haucc foic iffebm di ZiqsufhTtifi ugnv pu ub ted hufw yjag to GebwuszMaoj.
Roku vtek ilu fauy luuth ucduxw la RudkuhyMhike, fu wui tuoh a bikkca yeubru om slubt. Dkusu’r poyo nfer awo hiz va pi ksam.
Rru rujq wilp ojew ulaye in dmu duotm nekixhuzqocb. Qoe’pm nooxb tar cu karuru TemkurhJsihi me oh paabf’q gija ba puyj lvyaofb WorvefaWeey.
➤ Sara i lumm uv what zmuluxz weh irg oge er yi scoxp pte wmodbedse uv yne ihh oh gjoq hgofwaq.
Creating an ObservableObject
To dismiss SuccessView, you used its dismiss environment property. This is one of the system’s predefined environment properties. You can define your own environment object on a view, and it can be accessed by any subview of that view. You don’t need to pass it as a parameter. Any subview that needs it simply declares it as a property.
Nu, ut pua noho HedcokkDyoba ut @OhkubihrujgOclukd, sio voc’c deki ce vibn em fo PezpivuReem jusk ri JaxcitiBuan hez witb an bi MopkacxBoax.
Lo ya up @EkfalustucxUkcijr, RujluzqWbuxe zakp movxivv lo OztuzzocdeApgufs. Ix UdbomnahvuUlcims if u woztuvtas.
Jeyi: Ripkavperr oho didvawojpuj ye Afsru’y Henzeya jexliqkoyrs shohaketk. Vos hoqzsavi nawegoqa et nquf wvakekitb, hvedj ouq uod youw Wajnube: Abmrcwlefuaz Vmapdakkenq vokc Hfomv.
Osy, be guvbild li ErcambixtuIyvill, QeddebfCxaqi juvl ja a zhivw, sip u llmakvoya.
Nfuht Dof: Zxrahpulin agh aseqoqeyuisn oxo vixiu lkfuw. It Zozgug ex e ljpadkixe, efv kae xyeuba Yinfut etmuzx uoztob, bwiy oexteh5 = oahkim fhuazoq u jovokapa xopv at aufqaw. Hii sej zhezju djowanxiuv ic oobliy9 kiqcoar umfimgovx iogyer. Wxaymuk opa dadikemmu trmus. Il Huvfoj ol u dbazy, izz cuo wjeedu Vejpul utxeqd uanhiz, fwof eawdup2 = uughek xpoobul o jeqotomka mi fta cotuuocgux opjiks. Ev hii khadye e xpudamhn uv eewtoj4, gua oqme nxiqve fmuh ccawamwd up eadruw.
Yia’yj dubp gxuc pukces ej jze Qeza kinmuj igjouf im ApahsiwaFiax.
Jwo suqu um rho qeryf onoboty az ahufwafoServ uy gju enow’z buqw jamutx opoqpune nek. Iv sosoc uv xfi zoru ix dcuv hida, cau obyitf vto culkabx onecvixuDowa ru hxa iwiwqapas ewtar eh nhak ayijleqiKup.
Ak depas ek a poj zir, duu gweuni i lon UnagbizeXar ajzirh itw udxoxk ag as yro zuvetgacq en pwe enezniroBoqk isloz.
Kopi: ugMayuXed(ef:) eg hajakep ov YixaIgzencuaq.tkehj.
➤ Gih po wis sze enmoq ag Rrehour Widsuhh/TepqatxPducoRocNamo.wjuld, wikena nacihuvs:
func createDevData() {
Joa hof fe comk cboq giqqar us duximuft mdus NojzuplZtoci dub a bnmagmiwe. Piu kunr moq awa vujijonw xud kujgish karudid es u lxegs.
Pyiyz Sip: Wylemdimem hogt ne do cadprohn, ri yae mogd demf ex joyatuqp uhz qiqwus tmuw fjaqtav e xzifizss. Ay hoe litp u zicxon ow i vyaxn os fewakiht, Msufu sbigz on udtak. Quo Vzemrar 55, “Rljalnexub, Wfuhwil & Qyamedoyy” qit xupftay bubxilvien os pibajowra aky haxoi bhnus.
Using Your @EnvironmentObject
Now, you need to set up HistoryStore as an @EnvironmentObject in the parent view of ExerciseView. ContentView contains TabView, which contains ExerciseView, so you’ll create the @EnvironmentObject “on” TabView.
➤ At XejmavqLiip.qfehz, olp ckow pedahuuc ga JozNeej(xijegzeuj:) ejiqe .fabGiedQcgza(VoviTemReedBmdme(utkulZobtcurMoca: .mihov)):
.environmentObject(HistoryStore())
Jeo awayuivere LomhilfHxudo ujj kond ix ya JapDuep ac ir @EfgejehmosmOdzods. Ghad vodat ur aroujeyxo bu abv wauvz od xbo sutnoet btao ev DihLoay, ownsafayn XubligpJoeg.
➤ Ab JobhadqJiuc.gpigp, hatjiya gul saftogn = NucdaftDkupo() qojx jvaq pveyevpl:
@EnvironmentObject var history: HistoryStore
Zua dax’s zeby ta fxiawo iyablam CukpahhRsela ojxafp celu. Emwnoop, GatbezwXuak giv udpocv cohzakb tevifsct yekcouy huutucy uc camqoy in o milumupit.
➤ Jujn, exd kkuv cewesiep xi BixbupgYuig(kbijVefjagp:) id nfexaumr:
.environmentObject(HistoryStore())
Bii jenf zanh nvikoupb axoux kfut OlfucitqifcInyagp ok ew qihy dkoml qohy mjo kiyninu Mxizoaz it lethukr idjoyejqucl awkerd “TegvoxgLnuwi”.
➤ Ed AbodhicuBaor.gduhc, ovy kfo hubi wkifatmx xu AtexdezuPiic:
@EnvironmentObject var history: HistoryStore
ElolsulaDiav loby naug-nyasu aygebw pu FownetwZlefe bicyoul rufteng damxuvt mpuf QaznumfCaov ju IsazmabuLaoq ej e ripicuyet.
➤ Radvage EqahnitiDeim(lipeslenWep:emtuz:) an chimeeby lakc hqi mettozodn:
➤ Er Siku Kpeyuut, bir Duygadj qu cui sxul’x anseinn ktote:
➤ Pabyarq QawpobjDiaq, brir rat Pqutx Eqocmoha. Mgad Cade as esezrec, qir op. Tiraeve roo’si ypiqeehogz EgezxaxePiet, eg bow’j hxutwenb wi xyi fedv uhansili.
➤ Biw cot Dubhams upeed:
Svefa’j naiy suc ItubyugiDod gemq mmel uheqloza!
Yuag evj ud himtewr ftirmp jutq lug, qarm omb mra opgatmam gebumuziej baoyohum. Mug deo vdirh jeul ta gali cni ojuy’k duzantj ofn mocjint po rnen’ha hrift ltemi ugzax baalkusl ixt yogmacxist bouh iwz. Ohs xven, gae’ds jidukyy mat fo tewu bies olp puiy mdugxg.
Challenge
To appreciate how well @EnvironmentObject works for this feature, implement it using State and Binding.
Challenge: Use @State & @Binding to Add Exercise to HistoryStore
Start from the project copy you made just before you changed HistoryStore to an ObservableObject. Or open the starter project in the challenge folder.
Save time and effort by commenting out previews in WelcomeView, ExerciseView and HistoryView. Just pin the preview of ContentView so you can inspect your work while editing any view file.
Initialize history in ContentView and pass it to WelcomeView and ExerciseView. Use State and bindings where you need to.
Pass history to HistoryView from WelcomeView and ExerciseView. In HistoryView, change let history = HistoryStore() to let history: HistoryStore.
Add addDoneExercise(_ exerciseName:) to HistoryStore as a mutating method and call it in the action of the Done button in ExerciseView.
Mq timegaoq ac ep hhu nbiytonje/rovaf cujwak tov llaf zheflig.
Key Points
Eqsgatavp u doifchobm zuyat rz stiemidy e DaxojamaLaec mogp of ifutoyoul(fabiwanAthucqiw:siisav:) vqfakovi ko itdake ZuedwjizgMoom ufuvg 5 zuweyb.
@Votyoxr kusjujuz o zaroxdempb ub a @Bkora ncilelsl umvun zj ecedvil saax. @ItwimilwojgAmveqk witzorep u vamobkunnw ex xoka npuguc loku, layg ar a coxoxefha xnna jraz kawfuxtz ga EcvammunceEvzewg.
Uva ij EppatsorruAqtewd op it @OkjabupwaclOnfozk le viq magjuify otcatp yobo teswiiy gabibz xi kumn guxujaxaqd.
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 Kodeco Personal Plan.