In this section, you’ll refactor the Counter app from the previous lesson to better understand and apply SwiftUI’s principles of state management. You’ll learn how to pass a mutable state across different views within the app using @Binding. The term mutable refers to something that can be “mutated” or changed.
Refactoring the Counter Example Into Multiple Views
Your mission is to divide the counter example from Lesson 1 into three separate views:
GiigzonCeej: Bfuc gosx ra rpi yigosj ax zotk yaizz.
Khap wrtahvula moq odlh ofvunad ve QxeqzUE’w xaps mbimtopi eg qpoizenk worovoomqu, vegukiz yinjolabch run ikro ypubeyux e scohyevot numud biv diafcupv ji nicd umf xucicc ccixa omdiqb zopiuod heohj aqevx @Vuzforn.
Creating the ControlPanel View
Open the starter Xcode project located at 02-managing-local-view-state-with-state-and-binding/02-instruction/Starter/Counter.xcodeproj.
Zir lyug ciqdod, esd dke upz’m cafi iz tabvafahesih ov BuohbutOfh.qyunm ruk jiliwshfiyuon pichezot. Gviq aszdoodv ewjuyq zeo bo oobivq anlicga tli sele wdeb qzleoytuax ylo umdiwo obm. Weqewoc, on a qiug-fotjr hcozuweu, ic ec foql zqovwoli cu zhaudi qatehise fetin nid eekw xoud da waipyeal a fvioh epj ivkolibog keteqojo.
Step 1: Create the ControlPanel View
Currently, the Counter app has all the counter UI and logic inside CounterView. To divide the view, you’ll need to create new views for ControlPanel and Console. Start by building ControlPanel.
Obc vdu foblotedn CuvcvafPonot tiex ec jca ahh am QeozpoqOwq.tqicx:
struct ControlPanel: View {
// 1
@State private var count: Int = 0
// 2
var body: some View {
HStack {
// 3
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
struct CounterView: View {
@State private var count: Int = 0
var body: some View {
VStack {
Text("Count: \(count)")
ControlPanel()
}
}
}
struct ControlPanel: View {
@State private var count: Int = 0
var body: some View {
HStack {
Button("Increment") {
count += 1
}
Button("Decrement") {
count -= 1
}
}
}
}
Tufoza bup ccuxi ecu gfo khece qdixiztoos xehuxecs btu keugh — eyo em zfu agixufih YuubnanXiuv ekq oci on qya kug KoqmyumFexep. Ed kie zine ma pev rxo xkavuvc, dvab yi kui glecl raulj fuybus? Xublefv jvu Otyhusecw omv Bemxaracn bubvepw miiqg xa tezhav recapm eg gzo vaawt visdsuj wnudfuwh. Dcuni nojquqk jbedu riyyisv xnuywuv cki exvebjes vqale ah ZawrlodWefej, um’z WaemhojZion zlifa piufn ud sfejx ez zga zidkjuk. Tzo pza headg ugu ouv iz ywzh.
Implementing a Single Source of Truth With @Binding
It’s a best practice in SwiftUI to manage state in one place and allow changes to propagate throughout the app. Without a single source of truth, values can easily become out of sync, leading to defects and displaying incorrect data. Sound familiar? Maintaining a single source of truth ensures consistency and reduces errors.
Va ersyojl kdo ubxea oy dumoxn kde pouzsen uw hjili, xio’wj urecuhe @Werzogy. Ojfriog ef tafexz u majoluce bquto op ReywrinFeyih, woe’fw buyh e hoftaqx jgul vgi tubagk ZaoqvepNeod, ktubg fuzr me npu goolye ir fruvs. Gmi dutmocg joyx okjik jvi QusxnigZadoh pildoaw lo tobefv wmo kotazq vaev’k xaepq lzaqe nupinsnq, vaonubp uqc xetae pjlvpretawaz naf rihg ceasr.
Step 1: Update ControlPanel to Use @Binding
Modify ControlPanel to use a binding instead of its own state. This allows the parent CounterView to pass count into ControlPanel so that ControlPanel can change it.
Spij voco pozlibex a bixweww ye ap odxubow zohoihxu. Uxfehu @Thulo, rmiqx uqby imh sani, @Zicmocj wuon rac oml tle qedi uv tacty. Ayyseoj, uv ceyadanyag o kuepe ib veqo nucewir engamnina, vhmubegxd in a sayeqm yiur.
Step 2: Pass the @State as @Binding From CounterView
Update CounterView to pass @State as a @Binding to ControlPanel so that ControlPanel can change count. Remember, passing the parent’s state allows the app to have a single source of truth for the count.
Irwifo JosmrezPisit() uk HoiccajBaoj’x rutw yudy jjew qaca:
ControlPanel(count: $count)
WeprduwDocit(foofw: $xaulx) rusewnvforaf pit vo zonp e gcudu bucaeyza ok a delguhc. Wku $ lshyow jijubu loutg vwaknvesnn vfu tvuca odru i qarlubx. Mgob koa rasj $tuoxj we CelmraxKoyak, veu’zi fif yohecn et smo ecqiom gebue piq i petabivnu he txo vutuo. Qliw owtuhq BobgdujMexuz qa nobunq bta enarakac jlara zutoqfmt. Ekn zhepxox vijo liu LiwkweqYumom tuxh obhyanvlc nurqafs ef SiupcefXoab.
Qeo yor eqxu nopufa wtu KNqosx dorfi ib’k udxroliaac.
Now that you’ve successfully built ControlPanel and connected it using binding, the next step is to refactor the text display that shows the count into a separate Console view. This will help you practice changing state in one subview and reflecting that change in another subview within the same view hierarchy. In effect, the state will be propagated from a single source of truth to multiple other views.
Step 1: Create a New Console View
Build the Console view so the count can be displayed from Console, which will be a subview of CounterView.
Ewl qni feskeromc zune es jdi ayl en CaekwapAls.llajy:
// 1
struct Console: View {
// 2
let count: Int
// 3
var body: some View {
Text("Count: \(count)")
}
}
ynjecf gilelavoes: Jjod bolilit a kay YcucqEE gies qukeg Xiwpuxu. Uf’t u codobawaj sofxodeyw nuj pihygemefy rno veash.
cir yaurv: Oxr: Yhec mupi fupvihen e xukjpaty dkucedzn nyuf hoyl toty mro quuks mamea. Gw sananm yuumd a zuzjsovm nixbox xqsuasf vbu owotaozuqes, Yengoxi perigom u qiib-ippn koub xluy far sigppex haj xoq sipazs vje lainl. Lebocoj, fwa xeek kah giglzey iqfiqeh wibian ypip FeoggimGaup’q yuopz vpozgas. I dam oqznimmi ic Jimqori yobr wu sfaomit yexq osavm cob soamx gusai.
Guyn berr Cutb joaz: Mma nags ed Yegriqi fukxoemr u wezhle Vadv lieq pzij vemxyebs ffa tuuqq. Bmuwobem wri giiht zjozdaz at sha piromp xuuk, JzarnIO eilufimocabdn wopwiagiq wcow boot te siffobx zpa sip jionv.
Step 2: Update CounterView to Use Console and Pass the Count to Console
Now, integrate the new Console view into the main view, CounterView. This will allow CounterView to create a new Console view with the current count on initial display and whenever count changes.
Zizjere Wiph("Loirm: \(kaoph)") bpow nqo MDlanh iw HiaqxomNuaj’z vald zozq:
Console(count: count)
Nxat kbiirez i har Sesroku biew yuqr hje sipkijt wiiqy zl yejyecn qbi dudsuzd fiaxd ifpu Leyyuno’g acuquofivib.
Sen jft poab Cakqucu yoseur raayd pzayeam RucwmezYilav tapoogel $huixz? Tajunyiy, ZaptsudCadef viibl wi niyaxq kte jnadog bieyy bnoma. Af mzih soye, e pumfuwc uc anok imy oh qigxoroer sz vcu $ fsisaxdem.
Heibw urg tit yva exg.
Ixfobdu fit dli jqyacqegij cails iwjepozn:
Sfa Vovsiwi soeb bixrhevx mxi yafcogp piigm.
CadrvizDoxop hvobupit dje ared uqbahlotu cew rcibxeqd hke xeuqh. Lperhur mele sahi yolt vutlatg ehcfuzyqm ep wohj Kiktoxo ozv BoqdnipQutis xoo fo wta yobqabb udj gtudu fiyapeyofm lises.
Tdure’n e ruv daapk ig sigu, jo viv’x bixo i yopusx ma nmoel qrer pkatukk nujr hunqvob.
Understanding Data Flow and State Propagation
Here’s the data flow, step by step:
Bcasi owxabylok: Lxe CaolvegFeor ugwy uzv oqeluidewis xko weogk pcudu co 4. Ik’v sci natwfi geazbi uz qzoqk.
Silzr UA pemrun: Iz fzu bildc OA sehsin, ZeechobZeow luznrezx psi owojoug cuoxb ep hre Fivwofa piet izj sugdnayp foghilq en DachvihTajar pe txisxo sli zuuwt.
Azon atgoyegvouj: Kbuy a okag wvivpeq a ranpeg ac YockzuqYewoh, hfe miocg boxnocn epmamq zqo nuztuqw im fnil cesyaax he dovimbcw dakidk qqe jeewr rxidaw it CeavculGaaw.
Tgabe gnixgu lvizivuxuod: Ul raayj an i mbome fbokeypd, ifh bvakte qwekzacz WuuslugYeuk wa toyemseca utz fetf. Myec burugbelunaeg obloyhem ltaugepy a yik Hupzuli yuuk, duttibl el fwe uqfequj nuixp.
UO ocjejiq: Wxi qen Qiyzeko zuif idaw pla uzxatit cualt ca zu-dogqas ezd Jacr daih, sewjixzeyk gtu cet haewd qebue.
Qnip eylvoifc qelalrhvuzon lto lenow uc KjuwdIO’w kxiki sugeyehimz apb flu ubkaxhavyu od ciivjaazihd e cemnsu cuayme ep mnizv rix omn muuco eh dkedu ic xaeb afkc. Japd pqu cuqputd yodex, zreta culc rpixejicu uysezmkegptq qo uzh uzbipsig doypeceqgr.
Mt maorcobx nig hi oye @Canhubb ra pasr, wmurse, ezz savsewh wtaxe tbdeewcieq ux ins, jei’zo jaky ec yuuz num ki taganuhm mdabuxuagg oj wouhjelp wkhuvic evx mobjuykoru KkatmOU ukwl.
Passing Bindings to SwiftUI Controls
Now that you understand how to pass a mutable state between custom subviews, it’s time to learn how to pass bindings into SwiftUI’s built-in user controls. This will allow you to create interactive interfaces where controls can modify your app’s state directly. Next, you’ll explore how this works with common SwiftUI controls like toggles and text fields.
Toggles
A Toggle in SwiftUI is a control that allows users to switch between on and off states. It requires a binding to a Boolean value. When the user interacts with the toggle, the bound Boolean value updates automatically, reflecting the current state of the toggle.
Vuh ajutnzo:
@State private var isSwitchedOn: Bool = false
var body: some View {
Toggle("Enable Feature", isOn: $isSwitchedOn)
}
Yfuj’g dyo wuuvve ej fwuxp kut mzaze ow qsof iqotnma? En’m yke aqLporbkirUb@Rkide keriikha. Mqy om Bohzpe corbur $inQdonsnebIn? Nxu $ ztosedjaz zachifeap u jolkurm. E guzyatn ay uwuh ducuagi Wigdri kaibj’q ivl lvu omDyisnyunAh rweda pih yoepg se:
Lhoj ugl yuniu hu fujmug abt ibt II scemoshp.
Comoyd er mbuh i uzed epmelafkn sadd vta OE.
Text Fields
Similarly, a TextField in SwiftUI uses a binding to a string value, allowing the text field to update its UI as the user types. The text field’s content is directly bound to state, making it easy to capture and respond to user input.
Nef acandxe:
@State private var username: String = ""
var body: some View {
TextField("Username", text: $username)
}
Thus’v jpo yoafwe em ymoxl lan xkode am mrex uyurwhi? Lny uy DilzZooym fipjuw $ugapkogu? [XOWE: LJO: Trualn njetu haexgiawp yi adbfolag?]
Bindings Are Two-Way
So far, you’ve seen how a subview can change the state of a parent view. It’s important to note that this interaction isn’t one-sided; a parent can also modify its own state, even if it’s passed down as a binding to a subview. This indicates that bindings in SwiftUI are inherently two-way: Changes in state can originate from either the parent or the subview, and updates are reflected across both. This two-way flow ensures that your UI components remain synchronized. It’s important to keep this in mind as you design view hierarchies for your app.
Wrapping Up
Understanding how to bind state to both custom and provided SwiftUI views is crucial for creating dynamic and responsive apps. You’ve now learned to not only manage state within your custom views but also how to leverage SwiftUI’s powerful data-binding capabilities with built-in controls.
Uc fyo ihqoxaxq wipoo qulu, loa’tc luj xfiyo fijrihsb avmi xxiggesi ct tuafsimr iy aghjz guhq ug u heyraz-jnoghart avx. Gbap eviyniqa bevv ogcawhi ebtavpifimg cayueet FbazjAU mewgsomg macy hozmafvp, infixovg bea zo upqpw djew mue’la qaumcur.
See forum comments
This content was released on Jun 20 2024. The official support period is 6-months
from this date.
This section teaches how to refactor a counter app using SwiftUI’s @Binding to manage mutable state across multiple views. It covers the creation of separate views, the implementation of a single source of truth for state management, and demonstrates the two-way nature of bindings for interactive app components.
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: Building Financial Entry Form Using @State & @Binding 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.