iosswiftfoursquarecompletionhandlerdispatchgroup

How to make the for loop stop for the asynchronous request Swift 5


Here's the func that I want the for loop to wait for the completion from func getVenueDetails and if completion is true break out of the loop, and if not continue with the next venue id.

    func searchVenues(lat: Double, lng: Double) {
    let parameter: [String: String] = [
        "ll": "\(lat),\(lng)",
        "radius": "600",
        "limit": "10",
        "intent": "browse",
        "categoryId": "4bf58dd8d48988d1e4931735,4bf58dd8d48988d1f1931735,4deefb944765f83613cdba6e,4bf58dd8d48988d17f941735,52e81612bcbc57f1066b79eb,4bf58dd8d48988d181941735,4bf58dd8d48988d1f4931735,4bf58dd8d48988d189941735,4bf58dd8d48988d182941735,4bf58dd8d48988d17b941735,4bf58dd8d48988d163941735,4bf58dd8d48988d164941735,4bf58dd8d48988d165941735,56aa371be4b08b9a8d57356a,4bf58dd8d48988d12f941735"
    ];

    var isSent2: Bool = false


    client.request(path: "venues/search", parameter: parameter) { result in
        switch result {
        case let .success(data):

            let jsonResponse = try! JSONSerialization.jsonObject(with: data, options: [])
            let json = JSON(jsonResponse)

             let name = json["response"]["venues"][0]["name"].string
                print("NAME FROM JSON: ", name)

                let id = json["response"]["venues"][0]["id"].string
                print("id of foursquare", id)

            let group = DispatchGroup()

            group.notify(queue: .main) {


            for (key,subJson):(String, JSON) in json["response"]["venues"] {
               //group.enter()
                let placeName = subJson["name"].string
                print("place name:",placeName.unsafelyUnwrapped)

                let placeId = subJson["id"].string
                print("place id:",placeId.unsafelyUnwrapped)

                    group.enter()

                    self.getVenueDetails(id: placeId!) { (isSent) in

                        print("isSent", isSent)
                        isSent2 = isSent

                        group.leave()

                    }

               if (isSent2){
                      print("linaaa")
                //group.leave()
                break

                }

            }//end of for loop

            }
        //  print("json == ", jsonResponse)
        case let .failure(error):
            // Error handling
            switch error {
            case let .connectionError(connectionError):
                print(connectionError)
            case let .responseParseError(responseParseError):
                print(responseParseError)   // e.g. JSON text did not start with array or object and option to allow fragments not set.
            case let .apiError(apiError):
                print(apiError.errorType)   // e.g. endpoint_error
                print(apiError.errorDetail) // e.g. The requested path does not exist.
            }
        }
    }

}

here's the other function, where the request for venue details is made, so I want when the isSent returned true the for loop in searchVenues to stop (break) and if returned false to continue with next one.

func getVenueDetails(id: String, completionHandler: @escaping (Bool)->Void) {

    var isSent: Bool = false


    let parameter: [String: String] = [
        "VENUE_ID": "\(id)",

    ];

    client.request(path: "venues/\(id)", parameter: parameter) { result in

        switch result {
        case let .success(data):

            let jsonResponse = try! JSONSerialization.jsonObject(with: data, options: [])

            let json = JSON(jsonResponse)
            // print("json == ", jsonResponse)

            let name = json["response"]["venue"]["name"].string

            if let rating:Double = json["response"]["venue"]["rating"].double {
                print("rating from: ", rating)
                //rat = rating

                if (rating > 2)  {
                    self.foursquareNotification(name: name!)
                    print("here inside lol")
                    isSent = true
                    DispatchQueue.main.async {


                    completionHandler(isSent)
                    print("isSent hereee", isSent)

                    }
                } //end if
                else {
                    isSent = false
                    DispatchQueue.main.async {


                    completionHandler(isSent)
                    }
                }//end else
            } //end if rating

            //                rat = json["response"]["venue"]["rating"].double!
            //                print("rating from: ", rat)
            //                //rat = rating.unsafelyUnwrapped

        case let .failure(error):
            // Error handling
            switch error {
            case let .connectionError(connectionError):
                print(connectionError)
            case let .responseParseError(responseParseError):
                print(responseParseError)   // e.g. JSON text did not start with array or object and option to allow fragments not set.
            case let .apiError(apiError):
                print(apiError.errorType)   // e.g. endpoint_error
                print(apiError.errorDetail) // e.g. The requested path does not exist.
            }
        }
    }
    //return isSent
}//end getVenueDetails

Solution

  • You need to remove the for loop

    var res =  json["response"]["venues"] 
    

    Then

    var current = 0
    func start(item:ItemType) {
        let placeName = subJson["name"].string 
        let placeId = subJson["id"].string
         self.getVenueDetails(id: placeId!) { (isSent) in 
            if isSent {
                counter += 1
                start(nextItem)
         }
    }