0

This is how my Object classes looks like:

Workout.swift:

class Workout: Object {

    @objc dynamic var date: Date?
    // List of exercises (to-many relationship)
    var exercises = List<Exercise>()

}

Exercise.swift

class Exercise: Object {

    @objc dynamic var name: String?
    // List of sets (to-many relationship)
    var sets = List<Set>()
    var parentWorkout = LinkingObjects(fromType: Workout.self, property: "exercises")
}

Set.swift

class Set: Object {

    @objc dynamic var reps: Int = 0
    @objc dynamic var kg: Double = 0.0
    @objc dynamic var notes: String?
    // Define an inverse relationship to be able to access your parent workout for a particular set (if needed)
    var parentExercise = LinkingObjects(fromType: Exercise.self, property: "sets")

    convenience init(numReps: Int, weight: Double, aNote: String) {
       self.init()
       self.reps = numReps
       self.kg = weight
       self.notes = aNote
    }
}

I am trying to save this to realm using a buttonAction like this:

let newWorkout = Workout()
let newExercise = Exercise()
let newSet = Set() 

let nowDate = Date()
func saveWorkout() {
    if numberOfSets > 0 {

        print("Saving workout...")

        let realm = try! Realm()

        let cells = self.tableView.visibleCells as! Array<ExerciseCreatorCell>

        for cell in cells {
            if cell.kgTextField.text == ""  {
                cell.kgTextField.shake()
                return
            } else if cell.repsTextField.text == "" {
                cell.repsTextField.shake()
                return
            } else { // Add every single set
                newSet.reps = Int(cell.repsTextField.text!)!
                newSet.kg = Double(cell.kgTextField.text!)!
                newExercise.sets.append(newSet)
            }
        }

        print("NEXT")
        newExercise.name = exerciseNameButton.currentTitle


        newWorkout.exercises.append(newExercise)
        newWorkout.date = nowDate

        try! realm.write {
            realm.add(newWorkout)
            print("Saved!")
        }
    } else {
        let alert = UIAlertController(title: nil, message: "Please add any exercise before saving!", preferredStyle: UIAlertController.Style.alert)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

Each row in the UITableView indicates a workout set. The problem is; Let's say that I have added total 4 sets/rows, with different values for kg and reps for each set. After saving this, it saves the last set/row for all the 4 sets. Any tips?

Camile
  • 155
  • 3
  • 10
  • self.tableView.visibleCells is not recommended for the following reasons: 1. If you have more rows that can be displayed on scree, visiblecells have only those on screens. 2. Cells are reused. it's possible cell#10 has the same data as cell#1. For noe move newSet = Set() inside else { // Add every single set. It will fix it the save –  Dec 04 '19 at 22:33
  • 1
    @Sammy That worked, thanks! Do you have any other solution on how I can do it? Since the visible cell is not recommended? – Camile Dec 04 '19 at 22:48
  • 1
    Sammy is correct. On top of that, the best way is to save a new set every time your user enters one (which in turns creates a row inside your tableView). Why would you want to save all the rows at once? – rs7 Dec 04 '19 at 22:49
  • How do you save data(repsTextField.text and kgTextField.text) for each row? I assume user enters them. You need to have a delegate from cell to tableView Controller. When user enters data in those textFields, you save it into a variable –  Dec 05 '19 at 00:10
  • @rs7 I I thought this was the simplest solution. How can I do that? How can I save a new row each time, without saving the same row every single time? – Camile Dec 05 '19 at 14:46
  • It's really hard to answer this as I don't know how things are implemented. Assuming your user taps a button to add a new row (insert new row) and that the new row contains active textFields for him to enter values for that new set, you could have a save button so that when the user is done entering all the values they get saved into Realm. Now, to answer your question, when a new row gets added it gets added at the end of the tableView. So when your user taps the save button, you'll know that the new data that needs to get added to your Realm is located in the last row of the tableView. – rs7 Dec 05 '19 at 15:22
  • @rs7 What info do you need for create an answer post? The save button is just a normal button on the top left, and the button to add row is a button inside the footer. – Camile Dec 05 '19 at 15:52
  • A suggestion: trying to inline edit a tableView is usually extra challenging and more over - it's a very limited space for the user to work in. How about a Master-Detail view situation where the user taps a + button on the master view (with the tableView) when then segues to a detail view where the user can enter all of detail data about the workout, and then a Save button on that view? – Jay Dec 05 '19 at 16:56
  • As Jay suggested, you could segue (modal?) to a different view to prompt the user to add a new set. It's definitely easier to code. – rs7 Dec 05 '19 at 19:14
  • @Jay Like for example a UIAlertController with two textField's; One for reps, and one for kg, and a button to save? – Camile Dec 05 '19 at 19:31
  • @rs7 ^ Is this what you mean? – Camile Dec 05 '19 at 19:32
  • Yes, kinda. That's not really what a UIAlertController is for but it could be used that way. A Master-Detail would be a separate viewController with it's own UI that you would segue to from the main viewController. To see some super easy code, create a new project in XCode for iOS and select Master-Detail app. It's a great template that has exactly what we are referring to, and shows how to property segue from the master to the detail view. – Jay Dec 05 '19 at 19:59
  • @Jay Maybe the easiest way would be to create a grouped `UITableView` with one section for each exercise, and the section cells for sets, something like this: https://ibb.co/g6qd2TC . I added a thread here; https://stackoverflow.com/questions/59222206/create-grouped-uitableview-with-sections , but no useful response. – Camile Dec 07 '19 at 17:16
  • Well, crafting a grouped tableView like that is pretty straightforward. However I really don't link in-line editing of the table and would suggest (per above) a + button for each section that displays a detail view where the user would enter their data. Very similar to the Contacts app on the iphone. – Jay Dec 07 '19 at 17:32
  • @Jay So you do not suggest that I create a new section for each exercise that is going to be added into the workout? – Camile Dec 07 '19 at 17:42
  • Sure, you can do that. I was only suggesting that if you get too much data on the view at one time, it can become cluttered and hard to work with. Also, if you want to add data, its sometimes cleaner to have a separate view (a detail view) to add that on. – Jay Dec 07 '19 at 20:45
  • @Jay Ok, maybe I'll stick to using to the method I am currently using. But a questions; If a workout has already been created, how can I add a new exercise to that workout, without creating a whole new workout? – Camile Dec 07 '19 at 21:36
  • @rs7 Can you look at this: https://stackoverflow.com/questions/59230780/realm-add-list-object-to-already-existing-object – Camile Dec 08 '19 at 12:45

0 Answers0