Oleksandr Matrosov
Oleksandr Matrosov

Reputation: 27103

ParseSwift Relations Always Nil, Unable to Save Relations in Parse Backend

I'm working on an iOS app using the ParseSwift SDK, where I need to save an Exercise object that has relations to MuscleGroup (for primary and secondary muscles) and Equipment. However, even after saving the Exercise object, the relations (primaryMuscles, secondaryMuscles, equipment) remain nil and are not saved in the database.

I define my model as follows:

struct Exercise: ParseObject {
    var objectId: String?
    var name: String
    var isDefault: Bool
    var caloriesPerRep: Double
    var primaryMuscles: ParseRelation<MuscleGroup>?
    var secondaryMuscles: ParseRelation<MuscleGroup>?
    var equipment: ParseRelation<Equipment>?
    var image: ParseFile?
    var user: Pointer<User>?

    init(name: String, isDefault: Bool, caloriesPerRep: Double, image: ParseFile?) {
        self.name = name
        self.isDefault = isDefault
        self.caloriesPerRep = caloriesPerRep
        self.image = image
    }
}

My Save Code:

Here’s how I attempt to save the Exercise object and add relations:

@objc func saveButtonTapped() {
    guard let name = nameTextField.text,
          let calories = Double(caloriesTextField.text ?? "0"),
          let currentUser = User.current else {
        print("Error: User is not logged in or fields are missing.")
        return
    }

    let imageFile: ParseFile? = exerciseImage != nil ? ParseFile(name: "image.jpg", data: exerciseImage!.jpegData(compressionQuality: 0.8)!) : nil

    // Create a new Exercise object
    var newExercise = Exercise(name: name, isDefault: isDefaultSwitch.isOn, caloriesPerRep: calories, image: imageFile)

    // Attach the current user to the Exercise object
    do {
        newExercise.user = try Pointer(currentUser)
    } catch {
        print("Error creating user pointer: \(error.localizedDescription)")
        return
    }

    // Adding relations for primary muscles
    if !selectedPrimaryMuscles.isEmpty {
        print("Selected Primary Muscles: \(selectedPrimaryMuscles)")
        do {
            let primaryMuscleRelation = newExercise.primaryMuscles
            try primaryMuscleRelation?.add(selectedPrimaryMuscles) // Add selected primary muscles
        } catch {
            print("Error adding primary muscles: \(error.localizedDescription)")
        }
    }

    // Adding relations for secondary muscles
    if !selectedSecondaryMuscles.isEmpty {
        print("Selected Secondary Muscles: \(selectedSecondaryMuscles)")
        do {
            let secondaryMuscleRelation = newExercise.secondaryMuscles
            try secondaryMuscleRelation?.add(selectedSecondaryMuscles) // Add selected secondary muscles
        } catch {
            print("Error adding secondary muscles: \(error.localizedDescription)")
        }
    }

    // Adding relations for equipment
    if !selectedEquipment.isEmpty {
        print("Selected Equipment: \(selectedEquipment)")
        do {
            let equipmentRelation = newExercise.equipment
            try equipmentRelation?.add(selectedEquipment) // Add selected equipment
        } catch {
            print("Error adding equipment: \(error.localizedDescription)")
        }
    }

    // Save the exercise to the database
    newExercise.save { result in
        switch result {
        case .success(let savedExercise):
            print("Exercise saved: \(savedExercise)")
        case .failure(let error):
            print("Error saving Exercise: \(error.localizedDescription)")
        }
    }
}

Problem:

The Exercise object is saved successfully, but the relations (primaryMuscles, secondaryMuscles, equipment) remain nil in the database. When I try to add objects to these relations using add, they are still nil.

What I've Tried:

I've confirmed that the selected MuscleGroup and Equipment objects are valid before trying to add them to the relations.

Question:

Why are my relations (ParseRelation) still nil. How can I correctly add and save these relations using ParseSwift? Any help would be greatly appreciated!

Upvotes: 1

Views: 61

Answers (1)

Jay
Jay

Reputation: 35648

With the current implementation, I believe to create a pointer to the currentUser, that object would need to be persisted first. e.g. it needs to have it's objectId property populated.

You have a couple of options:

Option 1:

In the Exercise struct, change

var user: Pointer<User>?

to

var user: User?

then the user can be added to a exercise like this

newExercise.user = currentUser

The above works because the unsaved current user object is written along with the Exercise object.

Option 2:

Leave the struct the way it is and either save the CurrentUser object first and then add it as a pointer to the Exercise or modify an already saved Exercise with the saved currentUser. Something like

Task {
    let query = Exercise.query()
    let results = try await query.find()
    let exercise = results.first! //just getting the first one for this example

    let currentUser = UserStruct(userName: "Jay")
    let savedCurrentUser = try await currentUser.save()

    let changedExercise = try exercise.set(\.user, to: savedCurrentUser.toPointer())

    let savedChangedExercise = try await changedExercise.save()
}

Upvotes: 0

Related Questions