Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Binding and ForEach in SwiftUI

I can't undertand how to use @Binding in combination with ForEach in SwiftUI. Let's say I want to create a list of Toggles from an array of booleans.

struct ContentView: View {     @State private var boolArr = [false, false, true, true, false]      var body: some View {         List {             ForEach(boolArr, id: \.self) { boolVal in                 Toggle(isOn: $boolVal) {                     Text("Is \(boolVal ? "On":"Off")")                 }                             }         }     } } 

I don't know how to pass a binding to the bools inside the array to each Toggle. The code here above gives this error:

Use of unresolved identifier '$boolVal'

And ok, this is fine to me (of course). I tried:

struct ContentView: View {     @State private var boolArr = [false, false, true, true, false]      var body: some View {         List {             ForEach($boolArr, id: \.self) { boolVal in                 Toggle(isOn: boolVal) {                     Text("Is \(boolVal ? "On":"Off")")                 }                             }         }     } }  

This time the error is:

Referencing initializer 'init(_:id:content:)' on 'ForEach' requires that 'Binding' conform to 'Hashable'

Is there a way to solve this issue?

like image 597
matteopuc Avatar asked Aug 03 '19 17:08

matteopuc


2 Answers

You can use something like the code below. Note that you will get a deprecated warning, but to address that, check this other answer: https://stackoverflow.com/a/57333200/7786555

import SwiftUI  struct ContentView: View {     @State private var boolArr = [false, false, true, true, false]      var body: some View {         List {             ForEach(boolArr.indices) { idx in                 Toggle(isOn: self.$boolArr[idx]) {                     Text("boolVar = \(self.boolArr[idx] ? "ON":"OFF")")                 }             }         }     } } 
like image 51
kontiki Avatar answered Oct 08 '22 13:10

kontiki


⛔️ Don't use a Bad practice!

Most of the answers (including the @kontiki accepted answer) method cause the engine to rerender the entire UI on each change and Apple mentioned this as a bad practice at wwdc2021 (around time 7:40)


✅ Swift 5.5

From this version of swift, you can use binding array elements directly by passing in the bindable item like:

enter image description here

⚠️ Note that Swift 5.5 is not supported on iOS 14 and below but at least check for the os version and don't continue the bad practice!

like image 32
Mojtaba Hosseini Avatar answered Oct 08 '22 14:10

Mojtaba Hosseini