如何在 Swift (GCD) 中通知队列
How to notify a queue in Swift (GCD)
我正在使用 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 闭包不起作用,我无法正确调用 "main" 闭包。我究竟做错了什么?如有任何建议,我们将不胜感激。
试试这个改变:
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 {...}
.
中
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)
}
})
}
我正在使用 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 闭包不起作用,我无法正确调用 "main" 闭包。我究竟做错了什么?如有任何建议,我们将不胜感激。
试试这个改变:
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 {...}
.
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)
}
})
}