Soonmyun Jang
Soonmyun Jang

Reputation: 330

How to return values which affected by thread in Swift4

 func getAll(completion: (([Foods]?, Error?) -> Void)?){      
        var foodWithEname: [Foods]?
        let food: Food? = Food()
        var sortedFood: [Foods]?
        food?.getFoods(){ (foodsArray, error) in
            sortedFood = foodsArray?.sorted{ (left, right) in   
                if let lh = left.hits  {  
                    if let rh = right.hits {
                        return left.hits! > right.hits!
                    }
                    return true
                } else {
                    if let rh = right.hits {
                        return false
                    }
                    return false
                }
            }


            for fa in foodsArray! {

                var f = Foods(fid: fa.fid, fname: fa.fname, hits: fa.hits, addr: fa.addr, ename: nil)

                food?.getEffectsById(fa.fid){ (effectsArray, error) in
                    //foodWithEname?.ename = effectsArray
                    print ("11111")

                    DispatchQueue.global().async {
                        f.ename = effectsArray
                        print ("2222")
                        foodWithEname?.append(f)
                    }
                }

                DispatchQueue.global().async (execute: {
                    print ("00000")

                })

            }
            print("3333")
            completion?(foodWithEname, nil)
        }
        print ("4444")
    }

I need to return foodWithEname Value to the main view, but it returned without value because of thread flow...

I don't know how to control flow of closures.

I called the function in MainView:

let food: Food? = Food()
food?.getAll(){ (foodsArray, error) in

        }

And results: 4444 3333 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222 11111 2222

I want results like below:

2222 00000 11111 2222 00000 11111 2222 00000 ... 3333

And Array values should be in foodWithEname when completion?(foodWithEname, nil) is executed.

Please help to solve this problem, Thank you!

Upvotes: 0

Views: 694

Answers (2)

Mukesh
Mukesh

Reputation: 2902

In your second loop you're sending multiple asynchronous calls in a loop, and while the result is waiting you called the completion handler so the result is empty.

You need to call these asynchronous calls in a dispatch group and when all the executions are completed return the result to completion handler.

Do something like this in second loop:

// Create dispatch group
let group = DispatchGroup()

for fa in foodsArray! {

    var f = Foods(fid: fa.fid, fname: fa.fname, hits: fa.hits, addr: fa.addr, ename: nil)

    // Enter in group just before the call
    group.enter()

    food?.getEffectsById(fa.fid){ (effectsArray, error) in
        //foodWithEname?.ename = effectsArray
        print ("11111")

        DispatchQueue.global().async {
            f.ename = effectsArray
            print ("2222")

            // Leave the group when task is completed
            group.leave()

            foodWithEname?.append(f)
        }
    }

    DispatchQueue.global().async (execute: {
        print ("00000")

    })
}
print("3333")

// Wait for all tasks to complete, and call the completion handler
group.notify(queue: DispatchQueue.main) {
    completion?(foodWithEname, nil)
}

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100523

You need DispatchGroup to handle many asynchronous calls

func getAll(completion: (([Foods]?, Error?) -> Void)?){      
    var foodWithEname: [Foods]?
    let food: Food? = Food()
    var sortedFood: [Foods]?
    food?.getFoods(){ (foodsArray, error) in
        sortedFood = foodsArray?.sorted{ (left, right) in   
            if let lh = left.hits  {  
                if let rh = right.hits {
                    return left.hits! > right.hits!
                }
                return true
            } else {
                if let rh = right.hits {
                    return false
                }
                return false
            }
        }

      let dispatchGroup = DispatchGroup()

      for fa in foodsArray! {

            var f = Foods(fid: fa.fid, fname: fa.fname, hits: fa.hits, addr: fa.addr, ename: nil)

            dispatchGroup.enter()

            food?.getEffectsById(fa.fid){ (effectsArray, error) in

             f.ename = effectsArray

             foodWithEname?.append(f)

             dispatchGroup.leave()

            }


        }

        dispatchGroup.notify(queue: .main) {

             completion?(foodWithEname, nil)
        }


   }
 }

Upvotes: 1

Related Questions