代码之家  ›  专栏  ›  技术社区  ›  Max Kraev

如何在swift(gcd)中通知队列

  •  0
  • Max Kraev  · 技术社区  · 7 年前

    我正在使用gcd通知主线程(函数中有两个异步调用)

    我的代码:

    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 closure不起作用,我不能正确调用我的“main”closure。我做错什么了?任何建议都将不胜感激。

    2 回复  |  直到 7 年前
        1
  •  2
  •   OOPer    7 年前

    尝试此更改:

    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 ?? "")
        }
    })
    

    如马特评论中所述 defer 是一个很好的工具,总是在离开的时候做一些事情。


    这是另一个问题,但是同时从多个线程更新数组会导致一些问题。这种情况很少发生,所以很难修复。

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

        2
  •  -3
  •   Michaelcode    7 年前

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