如何在Swift(GCD)中通知队列

时间:2018-07-15 15:14:27

标签: swift grand-central-dispatch

我正在使用GCD通知主线程(该函数内部有2个异步调用)

我的代码:

func getWavesByMostRecent(closure: @escaping ([Wave]?) -> Void) {
    var waves = [Wave]()
    let dispatchGroup = DispatchGroup()

    self.query = DatabaseManager.waveRef.queryOrdered(byChild: Constants.reverseTimeStampKey)
    self.handle = self.query?.observe(.value, with: { (snapshot) in

        for value in snapshot.children {
            guard let wave = Wave(snapshot: value as! DataSnapshot) else { return }

            self.geoFire = GeoFire(firebaseRef: DatabaseManager.waveRef)
            let currentLocation = LocationManager.shared.getCurrentLocation()

            dispatchGroup.enter()
            self.geoFire?.getLocationForKey(wave.waveID, withCallback: { (location, error) in
                guard let location = location else { return }
                if error == nil {
                    if location.distance(from: currentLocation) < Constants.distance {
                        print("Wave", wave.waveID, "is in range")
                        waves.append(wave)
                    } else {
                        print("Wave", wave.waveID, "is out of range")
                    }
                } else {
                    print(error?.localizedDescription ?? "")
                }
                dispatchGroup.leave()
            })
        }
        dispatchGroup.notify(queue: .main) {
            print("THERE ARE SO MANY WAVES:", waves.count)
            closure(waves)
        }
    })
}

但是.notify闭包不起作用,我不能称呼我的“主要”闭包权利。我究竟做错了什么?任何建议将不胜感激。

2 个答案:

答案 0 :(得分:2)

尝试此更改:

self.geoFire?.getLocationForKey(wave.waveID, withCallback: { (location, error) in
    defer { dispatchGroup.leave() }
    guard let location = location else { return }
    if error == nil {
        if location.distance(from: currentLocation) < Constants.distance {
            print("Wave", wave.waveID, "is in range")
            waves.append(wave)
        } else {
            print("Wave", wave.waveID, "is out of range")
        }
    } else {
        print(error?.localizedDescription ?? "")
    }
})

如马特(Matt)的评论defer所述,它是一个总是在离开时做点什么的好工具。


这是另一个问题,但是同时从多个线程更新数组会导致一些问题。它很少发生,因此可能是一个难以修复的错误。

我不确定GeoFire是否在主线程中调用其回调,但是,如果不这样,则最好将所有回调代码包含在DispatchQueue.main.async {...}中。

答案 1 :(得分:-3)

dispatchGroup.leave()仍在闭包中,而是应位于for循环的末尾,如下所示:

func getWavesByMostRecent(closure: @escaping ([Wave]?) -> Void) {
    var waves = [Wave]()
    let dispatchGroup = DispatchGroup()

    self.query = DatabaseManager.waveRef.queryOrdered(byChild: Constants.reverseTimeStampKey)
    self.handle = self.query?.observe(.value, with: { (snapshot) in

        for value in snapshot.children {
            guard let wave = Wave(snapshot: value as! DataSnapshot) else { return }

            self.geoFire = GeoFire(firebaseRef: DatabaseManager.waveRef)
            let currentLocation = LocationManager.shared.getCurrentLocation()

            dispatchGroup.enter()
            self.geoFire?.getLocationForKey(wave.waveID, withCallback: { (location, error) in
                guard let location = location else { return }
                if error == nil {
                    if location.distance(from: currentLocation) < Constants.distance {
                        print("Wave", wave.waveID, "is in range")
                        waves.append(wave)
                    } else {
                        print("Wave", wave.waveID, "is out of range")
                    }
                } else {
                print(error?.localizedDescription ?? "")
                }
            })
            dispatchGroup.leave()
        }
        dispatchGroup.notify(queue: .main) {
            print("THERE ARE SO MANY WAVES:", waves.count)
            closure(waves)
        }
    })
}