NEW: Learn to build the incredible iOS 15 Weather app today! >>

Help with model concept for my app

Forums > Swift

Hi All,

I'm quite new to Swift, and not a particularly experienced programmer in general - trying to get better hence why I'm here, so apologies if what I write is nonsense!

I am trying to build an app to to help me with my work out sessions at the gym but at the moment I am struggling to comeup with a model which is flexible enough (and to be honest actually works!).

What I what to do is be able to build a workout "Program". A program will contain any number of "Sessions", a session will contain any number of "Exercises", and an exercise will contain the name of the exercise, how many times you need to do it and with what weight etc.

My current concept is to have a struct called exercise. This has the properties "name", "reps", "sets" and "intensity". I then have a class called "Session", which which has var exerciseArray - this is an array of type exercise (unsuprisingly). I then have another class called "Program", which has a var sessionArray, which again is a array of type session.

At the moment I am struggling to impliment this into my model as I can't find a way to dynamically spawn new session classes. Spawning new exercise stucts is fairly simple (probably mainly due to me plagerising the code from Pauls iExpense tutorial). So I can build one decent sessionArray, the issue comes when I try to spawn a new class to contain my next session.

Swift seems to force me into hard defining my "Session" class as a variable within my view, which means I can't find a way to fire a new Session class up when I'm done adding exercises to it. Which has started to make me wonder if there is a different better way to achieve this.

Hopefully my ramblings have suffciently interested someone to help thanks for reading!

Kind regards,

Adam

   

From your description, I would guess that the problem is not actually the model objects but rather the way you're wiring them up into your views. It's hard to be more precise without source code to look at, but I'd guess you're missing a step in terms of building your UI.

Try using a pen & paper design approach to draw the story of interactions in your app: launch the app and what gets displayed; user takes an action and what gets displayed; etc. My guess is that when you get to the point of editing a Session (adding Exercises) and you're done, then you'll tap some button that says, "Done" or something, and then you'll be taken to the current Program screen, where you'll have, what, a list of sessions? Then add a new item to that list and you'll be taken to the session editing screen? That's the point where you tell the session view what session it is editing: back while you're still actually displaying the program view and you're building the session view.

   

Hi sbeitzel,

Thanks for taking the time to respond to me.

Your post really helped. In the code I was talking about earlier I had no concept of a "veiw model". When you said about missing a step, I figured that my view was trying to directly manipulate my model rather than using a ViewModel class to manipulate the model.

I have now refactored my original classes Program, Session & Exercise into Structs and are manipultaing them using a class called ViewModel. This is working significantly better than it was before.

My guess is that when you get to the point of editing a Session (adding Exercises) and you're done, then you'll tap some button that says, "Done" or something, and then you'll be taken to the current Program screen, where you'll have, what, a list of sessions?

This is what I want eventually. At the moment I am just punting all the data at a single ugly view. In the future I will use a sheet to add an exercise to a session (like how Paul adds items to iExpense). I'm not 100% sure how sessions will be added to program though (as i think sheet in sheet is probably going to look quite bad).

At the moment the code looks like this:

Model:

import Foundation

struct Program: Identifiable {
    var id = UUID()

    var name = "program name"
    var sessionArray = [Session]()

    func createNewSession(name: String) -> Session {
        return Session(name: name)
    }

}

struct Session: Identifiable {
    var id = UUID()

    var name = "session name"
    var exerciseArray = [Exercise]()

    func createExercise(name: String, sets: Int, reps: Int, intensity: Int) -> Exercise {
        Exercise(name: name, sets: sets, reps: reps, intensity: intensity)
    }

}

struct Exercise: Identifiable {
    var id = UUID()

    var name = "exercise"
    var sets = 0
    var reps = 0
    var intensity = 0
}

View Model

import Foundation

class ViewModel: ObservableObject {
    @Published var program = Program()
    @Published var session = Session()
    @Published var exercise = Exercise()
}

View:

import SwiftUI

struct SessionBuilder: View {

//    @ObservedObject var topLevelContainer = TopLevelContainer()
//    @ObservedObject var session = Session()
//    @ObservedObject var program = Program()

    @ObservedObject var viewModel = ViewModel()

    @State var sessionName          = ""
    @State var exerciseName         = ""
    @State var exerciseReps         = ""
    @State var exerciseSets         = ""
    @State var exerciseIntensity    = ""

    var body: some View {
        NavigationView {
            VStack {
                Group {

                    TextField("\(viewModel.session.name)", text: $sessionName)

                    TextField("Exercise name", text: $exerciseName)
                        .keyboardType(.decimalPad)

                    TextField("Exercise reps", text: $exerciseReps)
                        .keyboardType(.decimalPad)

                    TextField("Exercise sets", text: $exerciseSets)
                        .keyboardType(.decimalPad)

                    TextField("Exercise intensity", text: $exerciseIntensity)
                        .keyboardType(.decimalPad)

                    Button("Add Exercise to Session") {
                        let newExercise = viewModel.session.createExercise(name: exerciseName, sets: Int(exerciseSets)!, reps: Int(exerciseReps)!, intensity: Int(exerciseIntensity)!)
                        viewModel.session.exerciseArray.append(newExercise)
                        exerciseName         = ""
                        exerciseReps         = ""
                        exerciseSets         = ""
                        exerciseIntensity    = ""
                    }

                    Button("Create Session") {
                        let newSession = viewModel.program.createNewSession(name: sessionName)
                        viewModel.program.sessionArray.append(newSession)
                    }
                }
                Group {
                    Spacer()
                    Text("Session preview: ")
                    Text(sessionName)
                    ForEach(viewModel.session.exerciseArray) { exercise in
                        Text("\(exercise.name) for \(exercise.sets) x \(exercise.reps) \(exercise.intensity)%")
                    }
                    Text("Program preview: ")
                    ForEach(viewModel.program.sessionArray) { session in
                        Text(session.name)
                    }
                }
            }
        }
    }
}

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

Its very ugly atm as I'm trying to get the base functionality working first. before worrying about making it look nice!

   

Okay, I'm glad you're making progress.

You said you were new to programming, so I hope you won't mind if I offer a piece of unsolicited advice. You said you want to get it to work and then worry about appearance afterward, and I get it -- that's productive. However, given the way SwiftUI works, you'll wind up doing even more work if you don't first think about the program's UI flow and dummy that up first. That will save you some real headaches if, 3/4 of the way through, you realize you want it to flow differently.

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.