arraysswiftuistructtogglemutating-function

Issues updating an element inside a struct within an array using a toggle in swiftui


Hi I'm a beginner coder in Swift and SwiftUI so I'm pretty sure this problem is due to a fundamental misunderstanding of what I'm doing. I'm trying to use a toggle to update a bool element of a struct stored in an array. The struct to be updated is selected by clicking on a navigationLink to a second page where the toggle is. Any assistance would be appreciated, I really think my problem is I don't even have the language required to properly google the information I need. Thank you in advance.

Here is a simple version of the code that I have put together so far:

File 1 (where I'm keeping my structs and arrays of structs:

import Foundation

struct DataModel: Identifiable {
    let id = UUID()
    let phoneExtension: Int
    var dataA: String
    var dataB: Bool

    mutating func toggleDataB() {
        dataB.toggle()
    }
}

var dataSet: [DataModel] = [
    DataModel(phoneExtension: 1000, dataA: "Hi Ho", dataB: true),
    DataModel(phoneExtension: 2000, dataA: "Hi Ho", dataB: false),
    DataModel(phoneExtension: 3000, dataA: "Please", dataB: true),
    DataModel(phoneExtension: 4000, dataA: "Work", dataB: false),
    DataModel(phoneExtension: 5000, dataA: "For Me", dataB: true)
]

File 2 - First Window when the app opens:

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationView{
            List{
                ForEach(dataSet.indices, id: \.self) { index in
                    NavigationLink("\(dataSet[index].phoneExtension)", destination: PlaygroundSecondPage(dataIsOn: dataSet[index].dataB, index: index))
                        .foregroundColor(dataSet[index].dataB ? .black : .blue)

                }
            }
        }
    }
}

File 3 Where you can change the toggle:


    import SwiftUI
    
    struct PlaygroundSecondPage: View {
        
        @State var dataIsOn: Bool
        var index: Int
        
        var body: some View {
            VStack{
                Text("dataIsOn: \(dataIsOn), in dataset: \(dataSet[index].dataB)")
                Toggle(
                    isOn: $dataIsOn,
                    label: {
                        Text("Toggle:")
                    })
                .onChange(of: dataIsOn) {
                    updateB()
                }
            }
        }
        
        func updateB() {
            dataSet[index].toggleDataB()
        }
    }


Solution

  • There are a lot of coding practices and concepts you need to master to make your code work. I suggest you keep learning SwiftUI and do the tutorials, there are very useful.

    Here is a version of your code that compile and run to help you start:

    struct DataModel: Identifiable {
        let id = UUID()
        let phoneExtension: Int
        var dataA: String
        var dataB: Bool
    }
    
    struct ContentView: View {
        @State private var dataSet: [DataModel] = [
            DataModel(phoneExtension: 1000, dataA: "Hi Ho", dataB: true),
            DataModel(phoneExtension: 2000, dataA: "Hi Ho", dataB: false),
            DataModel(phoneExtension: 3000, dataA: "Please", dataB: true),
            DataModel(phoneExtension: 4000, dataA: "Work", dataB: false),
            DataModel(phoneExtension: 5000, dataA: "For Me", dataB: true)
        ]
        
        var body: some View {
            NavigationStack{
                List($dataSet) { $item in
                    NavigationLink("\(item.phoneExtension)", destination: PlaygroundSecondPage(item: $item))
                        .foregroundColor(item.dataB ? .black : .blue)
                }
            }
            // to show all dataB
            Button("Test button") {
                dataSet.forEach { print($0) }
            }.buttonStyle(.borderedProminent)
        }
    }
    
    struct PlaygroundSecondPage: View {
        @Binding var item: DataModel
        
        var body: some View {
            VStack{
                Text("dataIsOn: \(item.dataB)")
                Toggle("Toggle:", isOn: $item.dataB)
                .onChange(of: item.dataB) {
                    updateB()
                }
            }
        }
        
        func updateB() {
            // item.dataB is already updated from the Toggle
            print("----> updateB item.dataB: \(item.dataB)")
        }
    }