-1
func fetchPlansOperation(planUUIDs : [String], completion : @escaping([Plan],[Int]) -> Void) {
        var plans = [Plan]()
        var workoutCountArr = [Int]()
        guard let uid = Auth.auth().currentUser?.uid else { return }
        
        let queue = OperationQueue()
        
        let fetchPlansOperation = BlockOperation {
            for planUUID in planUUIDs {
                REF_PLANS.child(planUUID).observe(.value) { snapshot in
                    guard let planDictionary = snapshot.value as? [String:Any] else { return }
                    let plan = Plan(uid : uid, planID: planUUID, dictionary: planDictionary)
                    print("FETCHED PLANS")
                    plans.append(plan)
                }
            }
        }
        
        let fetchWorkoutCountOperation = BlockOperation {
            for planUUID in planUUIDs {
                REF_PLANS.child(planUUID).child("workouts").observe(.value) { snapshot in
                    let workoutCount = snapshot.children.allObjects.count
                    print("FETCHED WORKOUTS")
                    workoutCountArr.append(workoutCount)
                }
            }
        }
        
        queue.addOperations([fetchPlansOperation,fetchWorkoutCountOperation], waitUntilFinished: true)
        print("ITS OVER..")
        
        
    }

The above code gives me this output :

ITS OVER.

FETCHED WORKOUTS

FETCHED PLANS

I want the Firebase fetch to be over and then print the "ITS OVER" statement. I need those values to perform further API fetches. What am I doing wrong here.

I know BlockOperations are asynchronous, meaning I have control over what starts but not what finishes. Is there any way I can make the Block Operation synchronous. I need those operations to finish before I can do something else. I need to fetch those values and then print "COMPLETED". Any help will be appreciated.

ParteekSJ
  • 9
  • 1
  • No. I'm refraining myself from using Dispatch Queues or Groups. I wanna perform all the fetches using Operations. – ParteekSJ Dec 25 '20 at 11:42
  • You have to wait / notify inside the operation blocks. – shallowThought Dec 25 '20 at 11:44
  • Have you tried using dependencies/barrier? :https://stackoverflow.com/a/42496559/986169 i.e. create a completion operation that executes after all other operations completed – giorashc Dec 25 '20 at 11:48
  • wait / notify as in group.wait() and group.notify() @shallowThought – ParteekSJ Dec 25 '20 at 11:50
  • @giorashc I've tried dependencies but I haven't tried barriers. With dependencies I get the final result first and then the fetching statement. – ParteekSJ Dec 25 '20 at 11:51
  • dependencies should work here. did you create an operation for completion as well? from your shared code the print "ITS OVER.." will always be first – giorashc Dec 25 '20 at 12:07
  • @giorashc OK! As you said I just added a new BlockOperation and put the "ITS OVER" statement there. I made the new BlockOperation dependent on the previous 2 Operations meaning the new one won't start until the previous ones are over and yet I still get the same result. "ITS OVER" gets printed first and then FETCHED PLANS and FETCHED WORKOUTS. – ParteekSJ Dec 25 '20 at 12:15
  • @ParteekSJ yes. That would be a working solution. – shallowThought Dec 25 '20 at 12:27
  • Actually if this is for iOS 13 and later I recommend switching to Combine. – matt Dec 25 '20 at 13:27

1 Answers1

0

You can block the operations until done:

    let fetchPlansOperation = BlockOperation {
        let group = DispatchGroup()
        for planUUID in planUUIDs {
            group.enter()
            REF_PLANS.child(planUUID).observe(.value) { snapshot in
                guard let planDictionary = snapshot.value as? [String:Any] else { return }
                let plan = Plan(uid : uid, planID: planUUID, dictionary: planDictionary)
                print("FETCHED PLANS")
                plans.append(plan)
                group.leave()
            }
        }
        group.wait()
    }

Do the same with the other operation.

shallowThought
  • 19,212
  • 9
  • 65
  • 112
  • You might consider using a proper asynchronous operation subclass rather than blocking threads with dispatch group `wait`. – Rob Dec 25 '20 at 16:44