How to notify a queue in Swift (GCD)

前端 未结 2 1388
悲哀的现实
悲哀的现实 2021-01-26 04:14

I\'m using GCD to notify main thread (have 2 async calls inside the function)

My code:

func getWavesByMostRecent(closure: @escaping ([Wave]?) -> Void)         


        
相关标签:
2条回答
  • 2021-01-26 05:19

    Try this change:

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

    As noted in matt's comment defer is a good tool to do something always when leaving.


    This is another issue, but updating an Array from multiple thread simultaneously would cause some problems. It rarely happens, so it can be a hard-to-fix bug.

    I'm not sure if GeoFire calls its callback in the main thread or not, but if not, you should better enclose all the callback code in DispatchQueue.main.async {...}.

    0 讨论(0)
  • 2021-01-26 05:19

    dispatchGroup.leave() is still in the closure, instead it should be at the end of the for loop like this:

    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)
            }
        })
    }
    
    0 讨论(0)
提交回复
热议问题