Search code examples
xcodeswiftuiapple-watchwatchos

Unable to place Bool value in a toggle in swiftui


Hey all I have been trying to fix this issue for 2 days now and just can't seem to get what I am lookinhg for.

My working code:

struct User: Decodable {
    let name: String
    let description: String
    let isOn: Bool
}

struct ContentView: View {
    @State var users = [User]()
    
    var body: some View {
        List{
            ForEach(users, id: \.name) { item in
                HStack {
                    Toggle(isOn: .constant(true)) {
                        Label {
                            Text(item.description)
                        } icon: {
                            //list.img
                        }
                    }
                }.padding(7)
            }
        }
        .onAppear(perform: loadData)
    }
    
    func loadData() {
        guard let url = URL(string: "https://-----.---/jsontest.json") else {
            print("Invalid URL")
            
            return
        }
        let request = URLRequest(url: url)
        
        URLSession.shared.dataTask(with: request) {data, response, error in
            if let data = data {
                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .iso8601
                
                if let decodedResponse = try?
                    decoder.decode([User].self, from: data) {
                    DispatchQueue.main.async {
                        self.users = decodedResponse
                    }
                    
                    return
                }
            }
            
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
        }.resume()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

the Json its pulling looks like this:

{
   "name": "J",
   "description": "Echo Show",
   "isOn": true
},...

Like I said above this code works as-is. Where the problem I am having comes into play is the toggle part. It doesn't seem to be happens with the item.isOn for seeing if its true or false. The only thing it likes is the .constant(). Naturally this will not work for my case due to me needing to change the toggles to either true or false.

If it's anything other than .constant it has the error of:

Cannot convert value of type 'Bool' to expected argument type 'Binding'

I can perhaps if I do this

@State var ison = false

var body: some View {
    List{
        ForEach(users, id: \.name) { item in
            HStack {
                Toggle(isOn: $ison)) {

That seems to take that error away.... but how can it get the value thats looping for isOn that way?

What am I missing here?


Solution

  • try this approach, making isOn a var in User, and using bindings, the $ in the ForEach and Toggle, works for me:

    struct User: Decodable {
        let name: String
        let description: String
        var isOn: Bool  // <-- here
    }
    
    struct ContentView: View {
        @State var users = [User]()
        
        var body: some View {
            List{
                ForEach($users, id: \.name) { $item in   // <-- here
                    HStack {
                        Toggle(isOn: $item.isOn) {  // <-- here
                            Label {
                                Text(item.description)
                            } icon: {
                                //list.img
                            }
                        }
                    }.padding(7)
                }
            }
            .onAppear(perform: loadData)
        }
        
        func loadData() {
            guard let url = URL(string: "https://-----.---/jsontest.json") else {
                print("Invalid URL")
                
                return
            }
            let request = URLRequest(url: url)
            URLSession.shared.dataTask(with: request) {data, response, error in
                if let data = data {
                    let decoder = JSONDecoder()
                    decoder.dateDecodingStrategy = .iso8601
                    if let decodedResponse = try?
                        decoder.decode([User].self, from: data) {
                        DispatchQueue.main.async {
                            self.users = decodedResponse
                        }
                        return
                    }
                }
                print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
            }.resume()
        }
    }