Good day! There are 2 functions with queries to VK, where one query uses the data of another: (runGroupSearch () and runGroupByID ()). The problem is that it is impossible to organize the work so that the second request starts its execution only after the first completes its execution and data is received. I want to make a parallel async to the main thread queue, already in which tasks are performed synchronously.

I assume that you will need GCD here. I tried to play in the Playground with sync and async streams of different quality. Everything is fine there, trouble here. If completionHandler (), then I do not know how to use it.

viewDidLoad ()

let userQueue = DispatchQueue.global(qos: .userInitiated) let utilityQueue = DispatchQueue.global(qos: .utility) override func viewDidLoad() { super.viewDidLoad() userQueue.async { self.userQueue.sync { self.testQueue() } self.userQueue.sync { self.runGroupSearch() } self.userQueue.sync { self.testQueue2() } self.utilityQueue.sync { self.runGroupByID() } self.utilityQueue.sync { self.quickSort(eventsArr: self.eventsArr) } self.utilityQueue.sync { self.CatalogTable!.reloadData() } } } 

The testQueue functions print the number 5 times. I use them to see what is happening in the log. And as for me, it is clear that functions are still executed asynchronously (2 testQueue functions can be executed at the same time, and they can, as in the log below. Always in different ways.)

Run log

For the queries themselves I use the SwiftyVK library.

Below is the code of functions with queries (they are declared in the class in which they are called):

 var ABC = ["в","с","до"] func runGroupSearch() { for i in 0..<ABC.count { let letter: String = ABC[i] VK.API.Groups.search([VK.Arg.q: "\(letter)", VK.Arg.type: "event", VK.Arg.cityId: "96", VK.Arg.future: "1", VK.Arg.count: "50"]).send( onSuccess: { response in print("SwiftyVK: Groups.search success \n \(response)") for j in 0..<response.count { let gid = response[j,"gid"].stringValue let name = response[j,"name"].stringValue let img = response[j,"photo_big"].stringValue if gid != "" && gid != " " { self.groupID.append(gid) self.groupName.append(name) self.groupImage.append(img) // убираем дубли self.groupID = Array(Set(self.groupID)) self.groupName = Array(Set(self.groupName)) self.groupImage = Array(Set(self.groupImage)) } } self.gIds = self.groupID.joined(separator: ",") print("gIds is:\(self.gIds)") }, onError: { error in print("SwiftyVK: Groups.search fail \n \(error)") } ) } } 

The code of the second function by the request that I want to call only after the first one is completed (data for the 2nd request in self.gIds):

 func runGroupByID() { print("gIds is:\(self.gIds)") VK.API.Groups.getById([VK.Arg.groupIds:"\(self.gIds)", VK.Arg.fields:"activity,members_count,start_date"]).send( onSuccess: { response in print("SwiftyVK: Groups.getById success \n \(response)") for i in 0..<response.count { if response[i,"is_closed"] == 0 { let memb = response[i,"members_count"].stringValue let dateStart = response[i,"start_date"].intValue let activity = response[i,"activity"].stringValue self.groupMembers_count.append(memb) self.groupStart_date.append(dateStart) self.groupActivity.append(activity) } else { self.groupMembers_count.append("no") self.groupActivity.append("no") } } print("StartDate: \n \(self.groupStart_date)") }, onError: { error in print("SwiftyVK: Groups.getById fail \n \(error)") } ) } 

Please tell me, really need help.

IOS 10 platform. *, Swift 3

    1 answer 1

    Well, if you want to call the second at the end of the first one, just insert the second one into the end of the onSuccess block onSuccess first one:

      } self.gIds = self.groupID.joined(separator: ",") print("gIds is:\(self.gIds)") self.runGroupByID() }, 

    Here you will not achieve anything using sync, because in your stream, you synchronously run asynchronous VK.API.Groups.search ..., then it does what it has to do, and your thread starts the next task.

    • Thanks for the answer! The problem is that I execute the first query in a loop (at each iteration I substitute an element of the ABC array with search words) and accumulating data, form the line self.gIds. I need to substitute this line in the 2nd request (it is executed once). Since the VK API restriction is 3 requests per second, then I will not be able to execute 2 requests at once in a loop (an error will be returned). Do I have a chance to make a synchronous request from async? - Ilia Fedorov
    • @IliaFedorov overlooked the cycle. If you do this, then you will need to wait for all the "first" requests to be executed before the second, plus you may have problems with variables, since they are pulled by different streams. Maybe better to alter the chain of requests? The first search was executed - the second search went, the search ended - the getById was called. - VAndrJ
    • You know, you really helped me a lot. Indeed, he did so, he built the second request (the self.runGroupByID () function) into the success block of the first, with one small condition: if self.ABC[i] == "до" { self.runGroupByID() } . Those. I go over the array ABC (search words) and because it is set manually and I know which element in the array is the last, then I made a condition for it (after executing the block's success code) ... As soon as the cycle reached it, then I start the trace. request. Thanks again! - Ilia Fedorov