1

I want to let queue1 finish and use the data I get in CardTheme and use this data to call the second API. I want to use the group.wait() to achieve this. But it stuck at all. It seems that my group is in main thread and cause the deadlock. I use the Moya package to call my API. How to wait one API's response back and use data call another API?

    let queue1 = DispatchQueue(label: "getBirthdayCardTheme", attributes: .concurrent)
    let queue2 = DispatchQueue(label: "getBirthdayCardDetail", attributes: .concurrent)
    let group = DispatchGroup()

    group.enter()
    queue1.async(group: group){
         InsuranceDataModel.shared.getCardTheme(completionHandler: {
            group.leave()
         },errorHandler:{
            group.leave()
                
         })
    }
    group.wait()
    group.enter()
    queue2.async(group: group){
        InsuranceDataModel.shared.getCardDetail(sender_theme_id: "", pageSize: "1", pageNow: "1", completionHandler: {
             group.leave()
        }, errorHandler: {
             group.leave()
        })
    }

I edit my code and this works great for a workaround.This weird that group.wait() can't use and cause view freeze.

    let group = DispatchGroup()
    group.enter()
    
    InsuranceDataModel.shared.getCardTheme(completionHandler: {
        //get sender_theme_id here
        group.leave()
    },errorHandler:{
        group.leave()
                
    })
    
    group.notify(.main){
        InsuranceDataModel.shared.getCardDetail(sender_theme_id: "", pageSize: "1", pageNow: "1", completionHandler: {
            
        }, errorHandler: {
        
        })
    }
frank61003
  • 205
  • 3
  • 16
  • Don’t wait, notify. Please learn to understand asynchronous data processing. Basically run the second task in the completion handler of the first. – vadian Aug 27 '20 at 12:29
  • @vadian I know the way that you said and this is my first thought. I want to know how to use DispatchQueue to get same effect and let code be cleaner. Thank you. – frank61003 Aug 28 '20 at 02:26
  • It's **not** the same effect. Forcing an asynchronous task to become synchronous is inefficient and bad practice. – vadian Aug 28 '20 at 03:26
  • @vadian but I need first API's response in order to call the second API. So It still need to wait the first API completion. I think this is Moya package's issue, because group.notify can work fine. – frank61003 Aug 28 '20 at 03:40

1 Answers1

1

Option 1: Just add them to the same queue and iOS will execute them one after another. https://developer.apple.com/documentation/dispatch/dispatchqueue

let queue1 = DispatchQueue(label: "oneQueue") // drop the .concurrent
queue1.async(/* getCardTheme task */)
queue1.async(/* getCardDetail task */)

Option 2:

InsuranceDataModel.shared.getCardTheme(completionHandler: {
    InsuranceDataModel.shared.getCardDetail(sender_theme_id: "", pageSize: "1", pageNow: "1", completionHandler: nil, errorHandler: {
                 // handle error?
            })
         },errorHandler:{
            // handle error?
         })
}

EDIT: Option 3 - exactly what you did, just don't use the .main queue

    let group = DispatchGroup()
    group.enter()
    
    let queue1 = DispatchQueue(label: "oneQueue") // drop the .concurrent
    queue1.async(execute: {
        debugPrint("Hi I am task 1");
        InsuranceDataModel.shared.getCardTheme(completionHandler: {
          group.leave()
        },errorHandler:{
          group.leave() 
        })
    })
    group.notify(queue: queue1, execute: {
        debugPrint("Hi I am task 2");
        InsuranceDataModel.shared.getCardDetail(/**/)
    })
    debugPrint("All Tasks Submitted")
Dima G
  • 1,945
  • 18
  • 22
  • I know the way that you said in option 2 and that is my first thought. I want to know how to use DispatchQueue to get same effect and let code be cleaner. What's you mean that add in the same queue? The API will create their own queue right ?Thank you. – frank61003 Aug 28 '20 at 02:34
  • Hi bro, I try your edited code. It doesn't work. Still can't wait first API's response to call second API. Really appreciate your comment. – frank61003 Sep 03 '20 at 10:53
  • Hi. Having another look at your question, the complication here is that your *getCardTheme* method is async by itself, which means inside getCardTheme you are starting another async task on *some* queue. I've added option 3 which is almost the same as what you did, just not on *.main* queue – Dima G Sep 03 '20 at 11:47