Home > Enterprise >  Swift / Firestore setData with multiple documents at once causes app to crash
Swift / Firestore setData with multiple documents at once causes app to crash

Time:09-21

I am creating a fitness app where you can favorite trainer accounts and when you favorite a trainer account I want to add all workouts posted by that trainer to the current user's feed.

When you favorite a trainer account I use this function to add the workouts to a collection on firestore:

func addToUserFeed() {
    guard let trainerUid = trainer.id else { return }
    guard let currentUid = AuthViewModel.shared.userSession?.uid else { return }

    COLLECTION_WORKOUTS.whereField("ownerUid", isEqualTo: trainerUid).addSnapshotListener { snapshot, _ in
        
        guard let workoutIDs = snapshot?.documents.map({ $0.documentID }) else { return }
        
        workoutIDs.forEach { id in
            COLLECTION_USERS.document(currentUid).collection("user-feed").document(id).setData([:])
        }

    }
}

Similarly, when you unfavorite a trainer I am removing those workouts from the user feed collection with this function:

func removeFromUserFeed() {
    guard let trainerUid = trainer.id else { return }
    guard let currentUid = AuthViewModel.shared.userSession?.uid else { return }

    COLLECTION_WORKOUTS.whereField("ownerUid", isEqualTo: trainerUid).addSnapshotListener { snapshot, _ in
        
        guard let workoutIDs = snapshot?.documents.map({ $0.documentID }) else { return }
        
        workoutIDs.forEach { id in
            COLLECTION_USERS.document(currentUid).collection("user-feed").document(id).delete()
        }

    }
}

Then to display these workouts on the feed page view in my app I fetch all the workouts in the user-feed collection on firestore with this function:

//FETCH WORKOUTS SAVED BY THE USER
func fetchFavoriteWorkouts() {

    guard let currentUid = AuthViewModel.shared.userSession?.uid else { return }

    COLLECTION_USERS.document(currentUid).collection("user-feed").addSnapshotListener { snapshot, _ in
        guard let workoutIDs = snapshot?.documents.map({ $0.documentID }) else { return }
        
        //THIS MAY CAUSE AN UNNECCESSARY AMOUNT OF WRITES TO THE APP
        self.workouts.removeAll()

        workoutIDs.forEach { id in
            COLLECTION_WORKOUTS.document(id).addSnapshotListener { snapshot, _ in
                guard let workout = try? snapshot?.data(as: Workout.self) else { return }
                self.workouts.append(workout)
                print("\(workoutIDs)")
            }
        }
    }
}

This is what the firestore collection looks like for user-feed. It adds workout ID documents to the collection that match up with workouts posting by the trainer you just favorited:

Firestore structure

This is working properly in a sense that when you favorite a trainer account it correctly adds multiple documents to the user-feed collection which correspond to workout IDs posted by the trainer you just favorited, however, when you favorite a trainer account the app just closes (not really crashes), and then when you re-open the app the user-feed correctly displays the workouts from trainers you have favorited.

Is there anything in my code that may be causing this random app close when you favorite a trainer?

I understand that this code may not be the most efficient, but I am really not focused on fixing that at the moment, just want to fix the random app close out.

Edit: The crash only happens when I favorite a trainer that has multiple workouts posted. So I guess something causes the crash when I add multiple documents to a collection at once? Because if I favorite a trainer that only has one workout then it adds that workout to my feed without crashing at all.

CodePudding user response:

the problem is caused by the listener getting called each time a workout is added to workout list and adding duplicated values to the list .

change addSnapshotListener to getDocuments fetchFavoriteWorkouts() and call this fetch function inside .onAppear() in feed View

  • Related