我有一个for循环,其结果从searchRequest到Google递增。我使用DispatchGroup来确保在更新UI之前从searchRequest获取所有数据。但是,没有调用我的dispatchGroup.notify函数,因此从未更新过我的UI。请参见下面的代码:

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()
    }
}

最佳答案

为了能够理解它的工作原理和用法,请先尝试简化代码,然后再使用所有功能进行扩展。

让我们看一下这段代码

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

09-06 17:47