0

I'm having a bit of a complicated construction and have trouble figuring out how to get it working:

class Parent : Codable, ObservableObject {
    @Published public var children: [Child]?

    public func getChildren(with name: String) -> [Child] {
        return children?.filter { $0.name == name } ?? []
    }
}

class Child : Codable, Hashable, ObservableObject {
    static func == (lhs: Child, rhs: Child) -> Bool {
        return lhs.name == rhs.name && lhs.isSomething == rhs.isSomething
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
        hasher.combine(isSomething)
    }

    let name: String
    @Published var isSomething: Bool
}

...

struct MyView : View {
    @ObservedObject var parent: Parent
    var names: [String]

    var body: some View {
        ForEach(names, id: \.self) { name in

            ...

            ForEach(parent.getChildren(with: name), id: \.self) { child in
                Toggle(isOn: child.$isSomething) { <== ERROR HERE
                    ...
                }
            }
        }
    }
}

I had also tried Toggle(isOn: $child.isSomething) which of course leads to Cannot find '$child' in scope.

How do I resolve this? In more detail: How do I return the correct type from getChildren() that allows $child.isSomething for example?

(BTW, I used this to allow an ObservableObject class to be Codable. Although this seems unrelated, I've let this into my code extraction above because perhaps it matters.)

meaning-matters
  • 21,929
  • 10
  • 82
  • 142

1 Answers1

-1

We can use separate @Published property with .onChange .

struct ContentView: View {
    @ObservedObject var parent: Parent
    @State var names: [String] = ["test1", "test2"]
    
    var body: some View {
        ForEach(names, id: \.self) { name in
            
            GroupBox { // just added for the clarity
                ForEach($parent.filteredChildren) { $child in
                    Toggle(isOn: $child.isSomething) {
                        Text(child.name)
                    }
                }
            }
        }
        .onChange(of: names) { newValue in
            parent.updateChildren(with: "test") //<- here
        }
        .onAppear{
            names.append("test3")
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(parent: Parent(children:[ Child(name: "test"), Child(name: "test2")]))
    }
}

class Parent: ObservableObject {
    init(children: [Child]) {
        self.children = children
    }
    @Published public var children: [Child]
    @Published public var filteredChildren: [Child] = []
    
    func updateChildren(with name: String) {
        filteredChildren = children.filter { $0.name == name }
    }
}

class Child: ObservableObject, Identifiable {
    init(name: String) {
        self.name = name
    }
    let id = UUID().uuidString
    let name: String
    @Published var isSomething: Bool = false
}
YodagamaHeshan
  • 4,996
  • 2
  • 26
  • 36