I am getting this error can anyone help please

I get this error. Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ff7b1af4f98)

I was hoping to load the view and input data from the questions. Then submit using the button and hoping I’ll send it to my back end and get results on my console

//
// LoseWeightNoEquipmentFitTest.swift
// MyExerciseApp
//
// Created by Tayami Rai on 25/04/2023.
//

import SwiftUI
import Foundation

struct LoseWeightNoEquipmentFitTest : View {

private let fitTestDone = FitTestDone()


@State private var burpees = 0
@State private var highTuckJumps = 0
@State private var jumpingJacks = 0
@State private var pushUps = 0
@State private var squats = 0

@State private var holdPlank = 0
@State private var holdSquat = 0
@State private var hold6Inches = 0

@State private var run1K = 0
@State private var walk1K = 0
@State private var activityLevel = 0

func getBurpeesData() -> Int {
    return burpees
}

func getHighTuckJumpsData() -> Int {
    return highTuckJumps
}

func getJumpingJacks() -> Int {
    return jumpingJacks
}

func getPushUps() -> Int {
    return pushUps
}

func getSqauts() -> Int {
    return squats
}

func getHoldPlank() -> Int {
    return holdPlank
}

func getHoldSquat() -> Int {
    return holdSquat
}

func getHold6Inches() -> Int {
    return hold6Inches
}

func getrun1K() -> Int {
    return run1K
}

func getWalk1K() -> Int {
    return walk1K
}

func getActivityLevel() -> Int {
    return activityLevel
}




private let numbers = Array (0...200)
private let staticHoldOptions = ["Choose", "<30s", "<45s", "<60s", "<90s", "90s+"]
private let running1kTimeOptions = ["Choose", "-5mins", "-6mins", "-7mins", "-8mins", "-9mins", "10mins+"]
private let walking1kTimeOptions = ["Choose", "-12mins", "-14mins", "-16mins", "-18mins", "19mins+"]

@State private var selectedActivityLevelKey = "None"


private let dailyActivityLevel: [String: Int] = ["Choose": 0 ,"Low": 1, "Medium": 2, "High": 3]

private var activityLevelKeys: [String]{
    dailyActivityLevel.keys.sorted()
}


var body: some View {

// NavigationView{

        Form{
            
            Section(header: Text("In a minute, how many can you do of the following:")){
                
                Picker("Burpees", selection: $burpees){
                    ForEach(numbers, id:\.self){
                        number in Text("\(number)").tag(number)
                    }
                }
                
                Picker("High jumps", selection: $highTuckJumps){
                    ForEach(numbers, id:\.self){
                        number in Text("\(number)").tag(number)
                    }
                }
                
                Picker("Jumping jacks", selection: $jumpingJacks){
                    ForEach(numbers, id:\.self){
                        number in Text("\(number)").tag(number)
                    }
                }
                
                Picker("Push ups", selection: $pushUps){
                    ForEach(numbers, id:\.self){
                        number in Text("\(number)").tag(number)
                    }
                }
               
                
                Picker("Squats", selection: $squats){
                    ForEach(numbers, id:\.self){
                        number in Text("\(number)").tag(number)
                    }
                }
                
            }
            
            Section(header: Text("How long can you hold?")){
                
                Picker("Plank", selection: $holdPlank){
                    ForEach(0..<staticHoldOptions.count, id:\.self){
                        index in Text(staticHoldOptions[index]).tag(index)
                    }
                }
                
                Picker("Squat hold", selection: $holdSquat){
                    ForEach(0..<staticHoldOptions.count, id:\.self){
                        index in Text(staticHoldOptions[index]).tag(index)
                    }
                }
                
                Picker("Six inches", selection: $hold6Inches){
                    ForEach(0..<staticHoldOptions.count, id:\.self){
                        index in Text(staticHoldOptions[index]).tag(index)
                    }
                }
                
            }
            
            Section(header: Text("How long to...")){
                Picker("Run 1km", selection: $run1K){
                    ForEach(0..<running1kTimeOptions.count, id:\.self){
                        index in Text(running1kTimeOptions[index]).tag(index)
                    }
                }
                if run1K == running1kTimeOptions.count - 1{
                    Picker("Walk 1km", selection: $walk1K){
                        ForEach(0..<walking1kTimeOptions.count, id:\.self){
                            index in Text(walking1kTimeOptions[index]).tag(index)
                        }
                    }
                }
            }
            
            Section(header: Text("What is your daily activity level?")){
                
                Picker("Activity Level", selection: $selectedActivityLevelKey){
                    ForEach(activityLevelKeys, id:\.self){key in
                        Text(key).tag(key)
                    }
                }
                
            }
       
            Button("Submit", action: {
                Task {
                    await fitTestDone.fetchPlan()
                }
            })
        

        }//End of form
        .navigationTitle("Fit test: Weight loss - no equipment")
        .navigationBarTitleDisplayMode(.inline)

    }


func saveLoseWeightNoEquipmentFitTestData(){

    let fitnessData = [
        "burpees": burpees,
        "highJumps": highTuckJumps,
        "jumpingJacks": jumpingJacks,
        "pushUps": pushUps,
        "squats": squats,
        "plankHold": holdPlank,
        "squatHold": holdSquat,
        "sixInchHold": hold6Inches,
        "run1km": run1K,
        "walk1k": walk1K
    ]
    //data stores all of the data the user inputs
    print(fitnessData)
    
}

}

struct LoseWeightNoEquipmentFitTest_Previews: PreviewProvider {
static var previews: some View {
LoseWeightNoEquipmentFitTest()
}
}

struct FitTestData : Codable{

let burpees: Int
let highTuckJumps: Int
let jumpingJacks: Int
let pushUps: Int
let squats: Int
let holdPlank: Int
let holdSquat: Int
let hold6Inches: Int
let run1K: Int
let walk1K: Int
let activityLevel: Int

}

class FitTestDone {

private let fitTestData = LoseWeightNoEquipmentFitTest()

func fetchPlan() async {
    
    let url = URL(string: "http://localhost:8080/api/v1/fitTest")!
    var request = URLRequest(url: url)

    let userFitTestData = FitTestData(burpees: fitTestData.getBurpeesData(),
                                  highTuckJumps: fitTestData.getHighTuckJumpsData(),
                                  jumpingJacks: fitTestData.getJumpingJacks(),
                                  pushUps: fitTestData.getPushUps(),
                                  squats: fitTestData.getSqauts(),
                                  holdPlank: fitTestData.getHoldPlank(),
                                  holdSquat: fitTestData.getHoldSquat(),
                                  hold6Inches: fitTestData.getHold6Inches(),
                                  run1K: fitTestData.getrun1K(),
                                  walk1K: fitTestData.getWalk1K(),
                                  activityLevel: fitTestData.getActivityLevel())
    
    let encoder = JSONEncoder()
    let fitTestData = try? encoder.encode(userFitTestData)
    
    request.httpMethod = "POST"
    request.httpBody = fitTestData
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    
    
    do{
        let (data, response) = try await URLSession.shared.data(for: request)
        print("⭕️ response is : \(response)")
        print("⚡️⚡️⚡️⚡️⚡️⚡️")
        
        let returnedData = String(decoding: data, as: UTF8.self)
        
        print("⭕️ returned data \(returnedData)")
        print("⚡️⚡️⚡️⚡️⚡️⚡️")

        let decoder = JSONDecoder()
        let plan = try decoder.decode(WorkoutOptions.self, from: data)
        print("⭕️ the plan is: \(plan)")
        print("⚡️⚡️⚡️⚡️⚡️⚡️")

    } catch {
        // handle errors
        print("⭕️ error \(error)")
    
    }
    
}

}

struct Combination: Codable {
let noOFRun: Int
let noOfTenK: Int
let noOfHit: Int

}

struct Option: Codable {
let activityLevel: Int
let hitLevel: Int
let runLevel: Int
let walkLevel: Int
let combination: Combination

}

struct WorkoutOptions: Codable {
let workoutOptions: [Option]
}

The error message is telling you your app crashed.

Start by adding an exception breakpoint to your project. Doing this will show you where in your code the app is crashing. Choose Debug > Breakpoints > Create Exception Breakpoint to add an exception breakpoint.

My guess is your app is crashing in the fetchPlan function, probably in the following line of code:

let fitTestData = try? encoder.encode(userFitTestData)

You should replace the call to try? with try. By using try?, you are discarding the error message. But if you have an error, you want to know the error message so you can fix the error.

Set a breakpoint at the start of the fetchPlan function and step through the code line by line. Make sure the userFitTestData variable has the value you expect.

If you haven’t used Xcode’s debugger before, the following article should help you:

An Introduction to Xcode’s Debugger

Hey! So i did what you said except removing the ? because it wouldn’t let me carry on with the debug. Anyways, i put a breakpoint at this bit:

struct LoseWeightNoEquipmentFitTest : View {

and it lead me to:

private let fitTestDone = FitTestDone()

i ‘stepped over’, but it didnt step over. Instead it refreshed and let me

private let fitTestDone = FitTestDone()

So after i ‘stepped in’, it took me to:

private let fitTestData = LoseWeightNoEquipmentFitTest()

i ‘stepped over’ and ‘steppd in’, but lead me back to:

private let fitTestDone = FitTestDone()

What happened when you set an exception breakpoint? Does the exception breakpoint fire?

What are you doing when the app crashes and you get the EXC_BAD_ACCESS error?

What happened when you set the breakpoint at the start of the fetchPlan function? Did Xcode pause your app there? What happened when you stepped through the code in that function? Does the userFitTestData variable have the value you expect?

If you have an error encoding your fitness test data to JSON, you are not going to see the error message if you continue to use try?. You said you couldn’t carry on with the debug when you used try. You have to stop running/debugging your project when you make changes to your source code.

The EXC_BAD_ACCESS error usually occurs when you try to access memory that has been deallocated or is otherwise inaccessible. In your code, there is a possibility that this error is caused by accessing an instance of LoseWeightNoEquipmentFitTest inside the FitTestDone class, which might not be the correct instance.

To fix the issue, you can pass the required data to the fetchPlan() function as parameters instead of accessing it through an instance of LoseWeightNoEquipmentFitTest .

First, modify the fetchPlan() function definition in the FitTestDone class:

func fetchPlan(burpees: Int, highTuckJumps: Int, jumpingJacks: Int, pushUps: Int, squats: Int, holdPlank: Int, holdSquat: Int, hold6Inches: Int, run1K: Int, walk1K: Int, activityLevel: Int) async {
    // ...
}

Next, update the fetchPlan() call inside the button’s action to pass the required data:

Button("Submit", action: {
    Task {
        await fitTestDone.fetchPlan(burpees: burpees, highTuckJumps: highTuckJumps, jumpingJacks: jumpingJacks, pushUps: pushUps, squats: squats, holdPlank: holdPlank, holdSquat: holdSquat, hold6Inches: hold6Inches, run1K: run1K, walk1K: walk1K, activityLevel: dailyActivityLevel[selectedActivityLevelKey] ?? 0)
    }
})

Lastly, remove the private let fitTestData = LoseWeightNoEquipmentFitTest() line from the FitTestDone class, since it is no longer needed.

By making these changes, you should be able to avoid the EXC_BAD_ACCESS error, and the data should be sent to the backend correctly.

Not 100% sure, but I hope it help.

Good luck!