0

I have a List that looks like that:

enter image description here

But when I click on one row, every circle in every row gets activated/deactivated. I am sitting on that problem for a few Hours now and don't know what to do. Can anyone help me?

I think the problem has something to do with the DispatchQueue.main.async Line. But if I don't use DispatchQueue.main.async in the code, the list is empty and cannot be filled. And if I wouldn't do DispatchQueue.main.async, I get the following Error twice:

Modifying state during view update, this will cause undefined behavior.

So if I use DispatchQueue.main.async the list can be filled and is not empty. But as I described earlier, the new Problem is, that when I click a Row, every Circle(from all rows) in the list gets activated/deactivated.

This is my code:

struct zettelDetailView: View {
    
    var info: CreateInfo
    
    @State var isChecked: Bool = false
    
    func toggle(){
        isChecked = !isChecked
    }
    
    @State var listItems = [CreateZettelDetailViewText]()
    @State var executeThisAsyncThing: Bool = true

    
        private func changeInfoListToArray() {
            
            //String ist folgendermaßen aufgebaut:
            //"Text/-t;" t = true; f = false "/-" und ";" sind splitter
    //        var returnArray = [CreateZettelDetailViewText]()
            
    //        let infoStr = info.list
            let infoStr = "Das-t;Ist-f;Ein-f;Test-t;"
            
            let infoArr1 = infoStr.split(separator: ";")
            
            var infoArr2 = [[String]]()
            
            print(infoArr1.count)
            
            if infoArr1.count != 0 {
                for i in 0...(infoArr1.count - 1) {
                    let x = infoArr1[i]
                    
                    let y = x.split(separator: "-")[0] //text
                    let z = x.split(separator: "-")[1] //bool
                    
                    var arr2 = [String]()
                    arr2.append(String(y))
                    arr2.append(String(z))

                    var zBool: Bool = false
                    if z == "t" {
                        zBool = true
                    } else if z == "f" {
                        zBool = false
                    }
                    
                    infoArr2.append(arr2)
                    
                    self.listItems.append(CreateZettelDetailViewText(text: "\(String(y))", isDone: zBool))
                    
                }
                            
            }
            
            executeThisAsyncThing = false

        }
    
    

    
    var body: some View {
        
//        listItems = changeInfoListToArray()
        

      DispatchQueue.main.async {
          if self.executeThisAsyncThing {
              self.changeInfoListToArray()
          }
      }
            
        
        return VStack {
            
            VStack {
                Text(info.name)
                   .font(.largeTitle)
                Text("\(info.day) - \(info.time)")
            }.offset(y: -50)
            
            
            List(listItems) { a in

                Button(action: self.toggle
//                    {
//
//                    if a.isDone {
//                        self.isChecked = true
//                    } else if !a.isDone {
//                        self.isChecked = false
//                    }
//
//                    print()
//                    print(a.id)
//                    print(a.text)
//                    print(a.isDone)
//                    print()
//
//                }
                ){
                    HStack {
                        Image(systemName: self.isChecked ? "checkmark.circle.fill" : "circle")
                        Text(a.text)
                    }
                }.onAppear() {
                    self.isChecked = true
                }

            }.offset(y: -50)


            Button(action: addRow) {
                Image(systemName: "plus.app.fill")
                    .offset(y: -20)
                    .font(.largeTitle)
            }




        }
        
    }
    
        private func addRow() {
                    
//            var arr = [[String]]()
//            arr = getZettelData()
//            arr.append(["ZettelName", "\(time)", "\(day)"])
//
//            let defaults = UserDefaults.standard
//            defaults.set(arr, forKey: "SavedZettelArray")

        }
    
    
}

1 Answer 1

3

There's only one isChecked for the entire list. Each row is using the same variable and so when one of them is tapped, all of them change.

Based on the code it looks like each item in the list has an isDone member. Try replacing self.isChecked with a.isDone for the Image name. Then try changing the button action from self.toggle to { a.isDone.toggle() }

So you're List would look like the following.

List(listItems) { a in
    Button(action: { 
        a.isDone.toggle()
    }){
        HStack {
            Image(systemName: a.isDone ? "checkmark.circle.fill" : "circle")
            Text(a.text)
        }
    }
}.offset(y: -50)
Sign up to request clarification or add additional context in comments.

4 Comments

This could've been posted as a comment. Add the method to fix OP's issue in your answer.
I agree. However, I don't have enough rep to comment. I'll add more to my response to make it a solution.
There is a new component in the beta version of SwiftUI called Label which has an image and text together. Can basically be used instead of the HStack. Does depend on the version of SwiftUI used though :)
I tried your solution, but It didn't worked for me because Cannot assign to property: 'a' is a 'let' constant do you have any Idea how I can toggle my a ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.