Reputation: 2503
There are several useful questions on this topic, but all I've found either use deprecated syntax from earlier betas (e.g., BindableObject) or do not require a binding be passed (e.g., to a Toggle).
I want to create a list of Toggles that are bound to elements in an array. I've tried many methods, but the syntax is never corrrect. The version below most closely matches the answers to an existing question.
struct Item: Identifiable {
var id: String { self.name }
var name: String
var enabled: Bool
}
final class ItemSet: ObservableObject {
@Published var items: [Item]
init() {
items = [
Item(name: "aaa", enabled: true),
Item(name: "bbb", enabled: false),
Item(name: "ccc", enabled: true)
]
}
}
var myItems = ItemSet()
struct ContentView: View {
@ObservedObject var items: ItemSet
var body: some View {
List {
ForEach(items.items) { item in
Toggle(item.name, isOn: $item.enabled)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(items: myItems)
}
}
The compiler error I get in Xcode 11.1 is:
Use of unresolved identifier '$item'
on the line where Toggle is defined.
I was under the impression that each Item
would itself need to be an ObservableObject
with a @Published var enabled: Bool
parameter, but I have not been able to get that working either, and all stackoverflow answers seems to say avoid making Item
itself ObservableObject
.
Any help would be much appreciated.
Upvotes: 1
Views: 1261
Reputation: 16327
You are confusing the property wrapper for items
(which is a current value subject) with the binding parameter that a Toggle
expects. See corrected implementation with binding below:
import SwiftUI
import Combine
struct Item: Identifiable {
var isEnabled: Binding<Bool>
var id: String { self.name }
var name: String
init(name: String, enabled enabledValue: Bool) {
self.name = name
let enabled = CurrentValueSubject<Bool, Never>(enabledValue)
isEnabled = Binding<Bool>(
get: { enabled.value },
set: { enabled.value = $0}
)
}
}
final class ItemSet: ObservableObject {
@Published var items: [Item]
init() {
items = [
Item(name: "aaa", enabled: true),
Item(name: "bbb", enabled: false),
Item(name: "ccc", enabled: true)
]
}
}
var myItems = ItemSet()
struct ContentView: View {
@ObservedObject var items: ItemSet
var body: some View {
List {
ForEach(items.items) { item in
Toggle(isOn: item.isEnabled, label: { Text (item.name) })
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(items: myItems)
}
}
Upvotes: 5