5

When I try to set show a toggle inside a loop of value from a dictionary, I get very little help from the error message.

If I un-comment the 3 lines of commented code below, trying to add a toggle for each of the properties in the loop, I get the following error:

Cannot convert value of type 'HStack, Text, ConditionalContent)>>' to closure result type '_'

import SwiftUI

struct properties {
    var id : Int
    var property : String
    var isOn : Bool
}

struct ContentView: View {

    @State var propertyValues: [properties] = [properties(id: 1, property: "DemoData", isOn: true),
                                                 properties(id: 2, property: "ShowLocalEvents", isOn: false)]

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach(propertyValues.identified(by: \.id)) { propertyValue in
                        HStack {
//                            Toggle(isOn: propertyValue.isOn) {
//                                Text("")
//                            }
                            Text("\(propertyValue.property)")
                            if propertyValue.isOn {
                                Text("On")
                            } else {
                                Text("Off")
                            }
                        }
                    }
                }
            }
        }
    }
}

1 Answers1

8

The issue here is that the initializer Toggle(isOn:label:) takes a Binding<Bool> for its isOn parameter rather than just a Bool. A Binding<_> is sort of a readable-writable "view" into a property that allows a control to update a value that it doesn't own and have those changes propagate out to whoever does own the property.

EDIT: I made this more complicated than it needed to be. The following works:

ForEach($propertyValues.identified(by: \.id.value)) { (propertyValue: Binding<properties>) in
    HStack {
        Toggle(isOn: propertyValue.isOn) {
            Text("")
        }
        // ...
    }
}

By using a $propertyValues, we are accessing a Binding to the array itself, which is transformed into bindings to each of the elements.

EDIT:

For the above to work, you'll need to add .value in a couple places in the body so that you are referring to the actual values and not the bindings to the values.

Jumhyn
  • 6,687
  • 9
  • 48
  • 76
  • Thanks for the additions on the Binding and the comment about value. Works well now. –  Jun 17 '19 at 22:19
  • But then how I can access propertyValue.property? ex. `ForEach($propertyValues.identified(by: \.id.value)) { (propertyValue: Binding) in HStack { Toggle(isOn: propertyValue.isOn) { Text(propertyValue.property) } // ... } }` – user1366265 Sep 23 '19 at 17:32
  • @user1366265 You should be able to access `propertyValue.property.value`. – Jumhyn Sep 23 '19 at 18:12
  • 1
    @Jumhyn I'm still struggling with this a bit, I'm getting "Unable to infer closure type in the current context" `ForEach ($thisCardData, id: \.self) { (card: Binding) in` thisCardData is of type [ICard] which is Identifiable, so I'm not sure I need the id: part of that ForEach statement. – Tom Millard Oct 14 '19 at 10:44
  • I do get this error... Generic struct 'ForEach' requires that 'Binding<[properties]>' conform to 'RandomAccessCollection'. what is that? – valeriana Jan 04 '21 at 01:57