DispatchGroup.notify не вызывается после для цикла swift xcode - PullRequest
0 голосов
/ 02 марта 2019

У меня есть цикл for, который увеличивает результаты поиска в Google Search по запросу.Я использую DispatchGroup, чтобы убедиться, что я получаю все данные из searchRequest перед обновлением пользовательского интерфейса.Однако моя функция dispatchGroup.notify не вызывается, и поэтому мой пользовательский интерфейс никогда не обновляется.См. Код ниже:

func donationCenters(completion: @escaping ([DonationCenter])->()) {

    var placeSearchQuery = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(String(self.coordinates.latitude)),\(String(self.coordinates.longitude))&radius=1500&keyword=donation center&key=###########"

    // GROUP CREATED
    let myGroup = DispatchGroup()

    placeSearchQuery = placeSearchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!

    var urlRequest = URLRequest(url: URL(string: placeSearchQuery)!)
    urlRequest.httpMethod = "GET"

    let task = URLSession.shared.dataTask(with: urlRequest) { (data, resopnse, error) in
        if error == nil {
            let jsonDict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
            if let dict = jsonDict as? Dictionary<String, AnyObject> {
                if let results = dict["results"] as? [Dictionary<String, AnyObject>] {
                    var donationCenters: [DonationCenter] = []


                    for result in results {
                        myGroup.enter() // ENTER GROUP
                            let donationCenter = DonationCenter(name: text, image: image, latitude: location["lat"] as! Double, longitude: location["lng"] as! Double, phone: formattedPhoneNumber, website: website)
                            donationCenters.append(donationCenter)
                            myGroup.leave() // LEAVE GROUP
                    }


                    // NOTIFY - NEVER CALLED (done never printed)
                    myGroup.notify(queue: .main) {
                        print("done")
                        completion(donationCenters)
                    }
                }
            }
        } else {
            // Error with search request
        }
    }
    task.resume()
}

ОБНОВЛЕННЫЙ КОД:

func donationCenters(completion: @escaping ([DonationCenter])->()) {
    if let coordinates = self.coordinates {
        var placeSearchQuery = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(String(coordinates.latitude)),\(String(coordinates.longitude))&radius=1500&keyword=donation center&key=###########"
        placeSearchQuery = placeSearchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
        var urlRequest = URLRequest(url: URL(string: placeSearchQuery)!)
        urlRequest.httpMethod = "GET"
        let task = URLSession.shared.dataTask(with: urlRequest) { (data, resopnse, error) in
            if error == nil {
                let jsonDict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
                if let dict = jsonDict as? Dictionary<String, AnyObject> {
                    if let results = dict["results"] as? [Dictionary<String, AnyObject>] {
                        var donationCenters: [DonationCenter] = []
                        for result in results {
                            let text = result["name"] as! String
                            if let images = result["photos"] as? [Dictionary<String, AnyObject>] {
                                if let photoReference = images[0]["photo_reference"] as? String {
                                    self.imageForPhotoReference(photoReference, completion: { image in
                                        if let image = image {
                                            if let placeId = result["place_id"] as? String {
                                                var placeDetailsQuery = "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(placeId)&fields=name,formatted_phone_number,website,formatted_address,geometry&key=########"
                                                placeDetailsQuery = placeDetailsQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
                                                var urlRequest = URLRequest(url: URL(string: placeDetailsQuery)!)
                                                urlRequest.httpMethod = "GET"
                                                let task = URLSession.shared.dataTask(with: urlRequest) { (data, resopnse, error) in
                                                    if error == nil {
                                                        let jsonDict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
                                                        if let dict = jsonDict as? Dictionary<String, AnyObject> {
                                                            if let result = dict["result"] as? Dictionary<String, AnyObject> {
                                                                if let formattedPhoneNumber = result["formatted_phone_number"] as? String {
                                                                    if let website = result["website"] as? String {
                                                                        if let geometry = result["geometry"] as? Dictionary<String, AnyObject> {
                                                                            if let location = geometry["location"] as? Dictionary<String, AnyObject> {




                                                                                let donationCenter = DonationCenter(name: text, image: image, latitude: location["lat"] as! Double, longitude: location["lng"] as! Double, phone: formattedPhoneNumber, website: website)
                                                                                donationCenters.append(donationCenter)



                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    } else {
                                                        //we have error connection google api
                                                    }
                                                }
                                                task.resume()
                                            }
                                        }
                                    })
                                    // IF EMPTY RETURN NO REGISTERED DONATION CENTERS IN YOUR AREA
                                }
                            }
                        }
                        print("done")
                        completion(donationCenters)
                    }
                }
            } else {
                // Error with search request
            }
        }
        task.resume()
    }
}

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

С некоторой помощью я обнаружил, что причиной возникновения проблемы является цикл for.Вместо этого я последовательно подключил несколько поисковых запросов следующим образом:

if results.count>0 {
            guard let placeId0 = results[0]["place_id"] as? String else { return }
            self.placeDetails(placeId0, completion: { (donationCenter0) in
                if results.count-1>0 {
                    guard let placeId1 = results[1]["place_id"] as? String else { return }
                    self.placeDetails(placeId1, completion: { (donationCenter1) in
                        if results.count-2>0 {
                            guard let placeId2 = results[2]["place_id"] as? String else { return }
                            self.placeDetails(placeId2, completion: { (donationCenter2) in
                                let donationCenters = [donationCenter0, donationCenter1, donationCenter2]
                                complete(donationCenters)
                            })
                        }
                    })
                }
            })
        }

Затем при завершении функции при вызове функции я заполняю массив и обновляю свой пользовательский интерфейс.Спасибо всем за помощь.

0 голосов
/ 03 марта 2019

Чтобы понять, как он работает и как его использовать, попробуйте сначала упростить свой код, а затем расширить его со всей своей функциональностью.

давайте посмотрим на эту часть вашего кода

for result in results {
    myGroup.enter() // ENTER GROUP
    let donationCenter = DonationCenter(name: text, image: image, latitude: location["lat"] as! Double, longitude: location["lng"] as! Double, phone: formattedPhoneNumber, website: website)
    donationCenters.append(donationCenter)
    myGroup.leave() // LEAVE GROUP
 }

, поскольку там есть только код синхронизации, он эквивалентен

for result in results {
    myGroup.enter()
    myGroup.leave()
}

и, наконец,

for result in results {}

Как видите, ваша группа там не имеет никакой функциональности!

откройте игровую площадку и попытайтесь понять, как использовать DispatchGroup для ваших требований (чтобы быть в курсе, когда все задние задания выполнены)

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

// it mimics some function which do some job in the background
// as dataTask in your example
func asyncFoo(id: Int, completition: @escaping (_ result: String)->()) {
    let q = DispatchQueue(label: "internal", qos: .background, attributes: .concurrent)
    q.async {
        // running in the backgroud
        var sum  = 0
        for i in 1...1000 {
            let r = Int.random(in: 0..<i)
            sum += r
        }
        let res = sum.description
        completition(res)
    }
}

let group = DispatchGroup()

for i in 0..<10 {
    group.enter() // enter the group before the task starts
    asyncFoo(id: i) { (result) in
        print("id:", i, result)
        group.leave() // leave the group when task finished
    }
}
group.notify(queue: .main) {
    print("all done")
    PlaygroundPage.current.finishExecution()
}

print("continue execution ...")

она печатает что-то вроде

continue execution ...    
id: 4 260320
id: 2 252045
id: 8 249323
id: 3 265640
id: 0 256478
id: 1 253038
id: 5 252521
id: 9 255435
id: 6 245125
id: 7 252262
all done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...