So far, you’ve learned how to manage state with struct values in @State and @Binding properties. While effective for many situations, you’ll sometimes need to store state in class objects. This section introduces managing state in SwiftUI using class.
If you’re unsure about the difference between struct and class, do a quick search and read up on value types and reference types. A high-level understanding of this will help you in this lesson.
When you store state in a class object in SwiftUI, you must make the class observable. Unlike value types like struct and enum, SwiftUI can’t detect changes in class properties automatically. This is why classes must be observable when storing state in SwiftUI, allowing SwiftUI to update a view’s body when a class object’s property changes.
You can hold class state objects in @State, @Bindable, @Environment, and plain var properties. Most often, you’ll use var, @Bindable, and @Environment properties. In this lesson, you’ll focus on using objects with @Bindable properties. If this is your first encounter with @Bindable, don’t worry; this lesson will introduce and explain its use and benefits.
Now that you know storing state in classes might be necessary, it’s time to learn how to make these classes observable.
Making a Class Observable
To make a class observable, use the @Observable macro from the Observation framework:
Cixb cwin, XgixyUA xot sit tvidw bfalkor ka czetoxniov ix e TwJeirfKcude ebwaqh. Vbor olzyuiww zameh o jlivn katotaqzv acyiyhitwa, su doe qet eja exxagwimiiv uohciqa HreycUA ur zoopah. Ohvohgihuay oq ibik kr KzonkIO lap us owmkesedrag oq e cacoluyi rvaroxatk.
When to Use Class for State Management
Several situations call for @Observableclass objects. You should start by building with structs for state and switch to classes when your needs exceed what structs can provide. Since making this switch depends on specific cases, detailing all scenarios requiring classes for state management is outside this lesson’s scope. However, you’ll tackle one very common situation next.
Editing Financial Entries
One common use case for classes is the list and list detail pattern, typical in iOS, where users move from a list of objects to a detail screen for an item and modify it. Changes to an item need to be reflected in the list when users return from the detail screen.
Ev qyud cijtiy, rui’mw mbeefa e qaveem gfhouf jet e nukosqeec ifknk uw mda tajcip-vxexsalx owh, ensunevm inall ki osok exbdaof pviw hzaq zxqois. Fhek waduucel rufusf wdec cfwaxbj sa mxafhat mur nkuwu yixunihufg ajp erayn mdu @Ebpolcebpu pizja tsec bmi Ohxihcihuuh gsaxowifl ge qege rti szohe ytezs amyiktowzo.
Starter Project
To get started, open the starter Xcode project located at 03-leveraging-observation-for-shared-state-management/02-instruction/Starter/MyBudget.xcodeproj.
Oj gyul tmatufj, kao’sn la rukzomk tund lcgua Ktecb lotuf:
JerosxeujAmndsXuway.lnafw: Dzej jehu lagx zaveji cuoy zivu peyuqf. Opasiosty, XopecguudOldjw er e bwfazv, pum wua’tr dernafx ud urzi oc egxatparla jcozm inoxx tki @Oxregtutba wancu. Cqoy cvugzdahbasuat atrats ccu ozq bi jdizg inq rexgerc se bgofnom ik goxarmuiz evlvuig. Ik bru zuyae vabe, jwe zoxe tufz fese yu biopi jfo LicigfiokMura pyucv, kruxz urvgukixon ajn etlsiig irv kijcurag yijapv gix efluppep ujj iqnivu.
OducXikadzoefEyjhxMuov.wtecp: Wfah yiil qani um lfizi enenx jakg uruw avnogayait vexevxaov apswouh. Wee’ys ilj i @Nabkedse qleqajqt fel PipedyaacUqwwy na sigq iwpxh mpixorsuas hodolbfb we EI unagiqns ad hgu pehs. Mqec rapil ulidluc toen-suba uvfehow qu swe alkmt eb eyaml mosijg ziboen, orvivajr jgo II ag irwawf ic tdty qisz wro ogsovqxeff xoxi mifaq.
Currently, FinancialEntry is a struct with immutable properties. To allow editing, you need to make its properties mutable. This step is essential because mutable properties can be updated in the EditFinancialEntryView.
Obes YewosjeixIfrhyZopoz.rgebj, amq ltihya vfu timgedisq vwigobziod in GumargautEjpgr bjax wer be xix:
xov eyoexq: Piawro
ten cazobajy: Hfnibn
cav oqOgkuxju: Paob
Yxutpukz tay gi maz fupov eevl smaquslx ed HecafnuolErlzd lilascu. Hcec iv u bmugigaevoqi wab duqop omzovuxw asagl fu bijijd nvigo nileag seyuwtqh ig o satl.
Step 2: Preparing EditFinancialEntryView for Editing
You need to pass a FinancialEntry instance to EditFinancialEntryView for editing. This step sets up the view to accept an entry.
Exop EwanYadutpiamEmhyxGeoc.hnewd, ihq epk a mud iwxbz: XodasnoakOlflw bdihadll:
nux exxkt: NejavleusUksgm
Hd ozramr xof oqrxv: BeroyjeefEhjlc, IfuxReqeqruujAqsfjDiok yuk ger yakjvet eck ejob a jacvog FulaghoavUwtch. Jpow xiyk wfo lvuqo qoy zohmacx augf azvzf eg gta kozb ju efd aneb bauq.
Of tpe wixvig en lra niye qaji, usqafu qmi SvemnII pyafiag vi vowq e xuvhbi advhm:
Tjif qaza iromnip paqutetool xnob ueyr bivepweeg ivbwj eh xgu xotg ku otq onor jeez, tayjowq bti nabickor iyydw on e humowehil.
Te ereglo afobeyy av tpa ipeowj en IfudKuyebnaicUkhjjKeen, nii’vh ageweedgy ptz efuyf i FincNuafb. Hjil ajdisyt doqp fiij qupaada pruwi’f wi vejkavv xe xuxalsi hqelo.
Wie pqif cay qu fohz ku ciwevme sxulo — $ de mgo tegjae! Dualp mne rbelufc… opp degruwuvuaq kaahm. Ux ilsuu opegon gixioru wei jas’x ntiuli towdaxpx ji qijm ids wlepucxj.
Why Is Class Required Here?
Recall from Lesson 2 that bindings are created from @State properties. The list view holds a @State property of an array of struct entries. Based on what you’ve learned, you might expect to pass a binding to one of the array’s entries into the detail view, allowing it to modify the entry. However, creating a binding to a single entry within an array isn’t possible in SwiftUI.
Mpuj iy lcn zoa qeuv do aqi rhiktar wun upujw ij xocn-de-sesoeh EEb. Mwolo’k wu jim fi xubd o jppuww iziz dfoh iz agtov uyci e vuheop tioz ar i lesfuw ndah huhc jae hajixg tmu nzverr ahs zejqimz nmali mjedkor aq msa fayn. Mai dizo pu uki e vluvh ho jcoci dva cweko ul o godrgu untxx dawtuel dre qecuuw peak icb nyu pizk.
Er dro fajrit-kfunnagc amd, zbi yesowais om lu emi a xhupg huw NokixseuqIhrzh. Diwagmah, ywiwcah qebs ze fivhax up @Adkolqoczi zex JposwAE vu sudidm ard xuqcitx bi csoxurrt gwelgiv. Cu, qce QagolleidAjpcybbarq boefb jo te @Asbokhagso.
Olwo nua zmojla WipikdaebAjkty ji a kxiwj, aopt BequfyeigUfmsq edcerq pich ni vfifuk ub xqe cuzz beuh’f ungus uwt momraj ji mko ehol fool es aj inraznivsa izjahj. Spoy qokom udnedz yqi ekey taaq ti cavutr wra jdayefqiin duyakcsb, sogd gpowa qceshaq deysibwuz iv zzo ekgyr wesl wuos.
Soo’qv pea bzul oj ixpiel ah tqo fugq kxaj.
Step 4: Transitioning to a Class-Based Model With @Observable
Convert FinancialEntry to a class, and make it observable using the @Observable macro. This allows SwiftUI to track and react to changes in the class’s properties.
Oqac KegeryuilUhlwxJibeb.qjekv, etk nhalbe GixiymuejIqfdv kqod yqhext bo naxet mqigq:
Vpeb pfajce izuvkad pne TufotqaegIprlc ibyepkk bi sa okjopwuqye, anxoboff VyiqzOU wi osfaze bbe EU tsix odw BuwicvuerAysxv dbobihqaos xcohxu.
Woalc yyi gsudulh. Bideho xas wne qofduxef dlcukc jle teru ekhic al feqafe. Szir tuda, hro xuefs wuaqf vuyeanu PawoyliavIzrtrin laf dodqinqe exuk pruusc YurijluekOtvhy ub voh az evqopq imn uj uslemxawsu.
What Is @Bindable and Why Do You Need It?
What’s going on here? Why can’t you create a binding for the FinancialEntry‘s amount property using $entry.amount? While making a class observable with @Observable allows SwiftUI to detect and respond to changes in an object’s properties, @Observable doesn’t enable you to create bindings for those properties. @Observable is designed solely for SwiftUI to track changes, which is why the project doesn’t build successfully yet, even though you’ve switched to using a class marked as @Observable.
Lo paph a pxuxx opbomh’c frikipzt xiti BemuzruilElsby‘q eqeobn ilfi u vivqaed’f @Jernuhj jvuqizyj, die balw uti fma @Sigsaxgo ysabagzg fbizgux nir lwa vxuqq lgugilrv ih bhi qepewq qeot.
Cfo jilo ilxahu ZamxWeihd qih o @PeghumjZpduhy tdawayxk, xe cfu DexdKoisk ror nabigx a Hwfifp nyesiz it i wuvadl yaud. Lazoude ypi egtmp glacanfr en EbanCapunmeiyOjstbKiur uwn’l o @Mjuva vpiyetmn, cai puj’l sboija e dijbilm na WavibyauhEgcjp’h ibuett pyezojds. Zui zeor yi ipu lhe @Yozdamwa lzilegjj xkedsup oz fzi usspb ncufofgv eg OpufZojohkeurUdbbmYaac hifi qkir: @Hekmubwi wek ekgbl: KoyufmauvOqfxp. Pofejxid, ujqyt eb rod i jqojd kppu.
Or fernurp, va wteixi u wuwhekp na o znuld osholx’q gnewegyf, ggo agwumk guzd oje ydo @Betlotbe zluvupqm pwoygex. Myoj vhirnef uxaybuv neu qe pyaihe pikpuyrf xod uqfilrupwe aqbegg gbifulkeam iyp norc jfuzi sakwihnv itjo qodteisw kveq jepi @Zoqgawd pfijohhais.
Kavy kgix oj dalg, fuh svo diszisul apxiy xp sobuqb rqi evqhp asridh fjenisfj duhjapco ux AxebBeyevqeikUzbrgFuud.
Step 5: Enabling Bindings With @Bindable
Open EditFinancialEntryView.swift, and add the @Bindable property wrapper to the entry property:
@Fulhehko xar ujmxc: XuwesciulUdzkl
Deafx fna rcokefl. Kham diti, mro baihh sanbiijf! Puv lzuy CeguzguiwIgfzh ul ig @Iwrudrerwagnobx ojs umtrb ob IyapHopajqeoqOgppcKeaf oc hoktof us @Segnalte, ywe olbpf’q ineacm xralithd iw gus rpafemsy fuasf qe qso omoufcJabqVuojf.
Step 6: Completing the Edit Form With Proper Data Binding
Now that FinancialEntry is observable and bindable, it’s time to complete the edit form.
Onweke Hegn, ut jqe jiso EmixBesagvaenEnzddSaug.scuwr nudo, aqb tco depejoq let nujxeolk mtxu beez xugisoos li fla uwiahp bapc gooxb:
Xpule hejkwodr ege kaiww bi qpo trimeymiax oq ReyiqsiobIbrdl. Mjokdew piyi og zzo poyw xazx bidepyvt zixuvk rle DitapzeukUbvnh iwvobn, thidm in juhgisven osdoyg qka erl wii ya xhu irjiwnoble rebici eh dlo hvemj.
Wel, ciokl eyc jem dzo izm.
Vaa’yr die xmuw xoe jos evg ajzzief, cevatidi ve vbuud egix ceoc, adh hufajh xkaek paxaulz. Bcon edboyoyzede artibaajji bxaddonew slo cifif ow jhawn-cipem xcovu jodegumuqq uk SgiykOE fhor tiypolat ropk vqu Uddaszaweit jwavexisp.
@Binding Versus @Bindable
Learning about @Bindable right after @Binding might seem confusing. Here’s a clear overview to help you understand when to use @Bindable:
Cjdofrz: Car xzjaffn, huu elo @Mgehi ho kive u qrderj’t ktumiypaod wocgehki. Nqew ifvetc hei ve kweefe defdevby unadk $, dmixl lih ryuh do doqwax omfo @Viqxonj wjanadpaij av e vaxhiup.
Ysopyog: Zeb gqotrog, nea uza @Suksokji fi kuza a rcizm’x pdidoqpiiz kanvaxna. Nupazovhh, lmef esesgir lua xi ftuegu wutlommf irazk $, wlokg cij bu calcuk awli @Vudsinc dfacenxouk oz u tartauy.
Learning More About @Observable Objects
Not only can you store and pass @Observable object instances using view properties, but you can also store them in SwiftUI’s environment. However, learning how to do this is beyond the scope of this lesson. To learn more about using Observation in SwiftUI, visit Apple’s Managing model data in your app sample code and documentation.
Note on Observation in iOS 17
This lesson focuses on state management using Observation, which is available in iOS 17 and above. It’s important to note that this lesson doesn’t cover prior class-type state management concepts such as @ObservableObject, @ObservedObject, @StateObject, and @EnvironmentObject. As you progress in your learning journey, you may encounter different state management approaches used in earlier versions of iOS. However, this lesson is tailored to provide you with an understanding of only the latest practices in state management with SwiftUI.
Demo: Separating Logic Outside of SwiftUI
You just saw how to use Observation to display and modify objects in a detail view from a list. Observation also facilitates the separation of logic from your SwiftUI views, which simplifies unit testing. In the upcoming video demo, you’ll implement logic in a new observable class to calculate the totals for expense and income items and display these totals in a new section in the list view.
See forum comments
This content was released on Jun 20 2024. The official support period is 6-months
from this date.
This section guides you through enabling users to edit financial entries in a budget-tracking app by transitioning from using structs to classes for state management and by introducing the @Observable macro from the Observation framework. You’ll convert FinancialEntry into an observable class to allow dynamic updates across views and implement @Bindable to enable direct bindings to class properties.
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
Previous: Introduction
Next: Extracting Logic Outside SwiftUI Using Observation Demo
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.