Grand Central Dispatch 多个 DispatchGroups
Grand Central Dispatch Multiple DispatchGroups
我有三个异步调用。一份 returns 数据,两份 return 图片来自使用 firebase 的 S3。我有一个后台 DispatchQueue 和三个调度组。我需要一种方法让他们同步执行,但他们没有!我什么都试过了,.notify 立即执行,这是错误的。
这个的输出是:
图片完成
全部完成
group.notify 完成
getImages() 完成
我想理解的是为什么imagesdone在group.notify完成之前执行?我需要执行第一个组,然后是 imagesGroup,然后是 avaGroup。
我基本上有三个异步调用,第二个/第三个可能是多个异步调用。我如何等待它们完成,然后执行后续调用?
func loadFriendPhotos() {
let backgroundQueue = DispatchQueue(label: "com.app.queue",
qos: .utility,
target: nil)
let group = DispatchGroup()
let imageGroup = DispatchGroup()
let avaGroup = DispatchGroup()
typealias tempAlias = (username:String, imageURL: String, pathUrl:String)
var tempAliasArray = [tempAlias]()
var imageArray = [UIImage]()
var avaImageArray = [UIImage]()
group.enter()
let workItem = DispatchWorkItem {
databaseRef.child("friendPhotos").child(globalUsername).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
let enumerator = snapshot.children
var childrenCount = snapshot.childrenCount
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
let name = rest.childSnapshot(forPath: "username").value as! String
let downloadURL = rest.childSnapshot(forPath: "downloadURL").value as! String
let uid = rest.childSnapshot(forPath: "uid").value as! String
let pathURL = rest.childSnapshot(forPath: "pathURL").value as! String
let downloadURLRef = storage.reference(forURL: downloadURL)
let newTempAlias = tempAlias(name, downloadURL, pathURL)
tempAliasArray.append(newTempAlias)
}
group.leave()
}
})
}
func getAvaImages() {
for index in tempAliasArray{
avaGroup.enter()
let avaItem = DispatchWorkItem {
let avaURLRef = storage.reference(forURL: index.1)
avaURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
if (error == nil) {
print("success!")
let picData = UIImage(data:data!)
avaImageArray.append(picData!)
} else {
print(error?.localizedDescription)
}
print("we left getAvaImages()")
avaGroup.leave()
}
}
backgroundQueue.async(execute: avaItem)
}
}
func getImages() {
for index in tempAliasArray{
imageGroup.enter()
let imageItem = DispatchWorkItem {
let downloadURLRef = storage.reference(forURL: index.1)
downloadURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
if (error == nil) {
let picData = UIImage(data:data!)
imageArray.append(picData!)
} else {
print(error?.localizedDescription)
}
print("we left getImages()")
imageGroup.leave()
}
}
backgroundQueue.async(execute: imageItem)
}
}
backgroundQueue.sync(execute: workItem)
group.notify(queue: DispatchQueue.main, execute: {
print("group.notify is done")
getImages()
})
imageGroup.notify(queue: DispatchQueue.main, execute: {
print("images done")
getAvaImages()
})
avaGroup.notify(queue: DispatchQueue.main, execute: {
print("all is done")
})
}
您在 imageGroup
中没有任何内容时调用 imageGroup.notify
,因此它会立即通知。同样,avaGroup
会立即通知,因为在您调用它时它是空的。
但是我不明白所有的间接寻址和分组以及三个数组。为什么在处理每张图片之前必须等待所有图片下载?为什么不直接在原始循环中为一个元素启动下一步呢?像这样:
var allTheResults = []
group.enter() // Enter once for the top-level
kickOffAsyncWithCompletion { resultList in
for item in resultList {
let resultThing = doSomeStuffToSetupNextLevel()
group.enter() // Enter once per thing we iterate over
kickOffNestedAsync(with: resultThing, completion: { result in
let finalResult = computeFinalResult(fromResult: result)
allTheResults.append(finalResult)
group.leave() // leave once per thing we iterate over
})
}
group.leave() // leave once for the top level
}
group.notify { doThing(withFinalResults: allTheResults) }
如果您想协调一组操作的端点,您希望所有这些操作都与同一个组一起工作,而不是每个操作单独的组。
我有三个异步调用。一份 returns 数据,两份 return 图片来自使用 firebase 的 S3。我有一个后台 DispatchQueue 和三个调度组。我需要一种方法让他们同步执行,但他们没有!我什么都试过了,.notify 立即执行,这是错误的。
这个的输出是:
图片完成
全部完成
group.notify 完成
getImages() 完成
我想理解的是为什么imagesdone在group.notify完成之前执行?我需要执行第一个组,然后是 imagesGroup,然后是 avaGroup。
我基本上有三个异步调用,第二个/第三个可能是多个异步调用。我如何等待它们完成,然后执行后续调用?
func loadFriendPhotos() {
let backgroundQueue = DispatchQueue(label: "com.app.queue",
qos: .utility,
target: nil)
let group = DispatchGroup()
let imageGroup = DispatchGroup()
let avaGroup = DispatchGroup()
typealias tempAlias = (username:String, imageURL: String, pathUrl:String)
var tempAliasArray = [tempAlias]()
var imageArray = [UIImage]()
var avaImageArray = [UIImage]()
group.enter()
let workItem = DispatchWorkItem {
databaseRef.child("friendPhotos").child(globalUsername).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
let enumerator = snapshot.children
var childrenCount = snapshot.childrenCount
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
let name = rest.childSnapshot(forPath: "username").value as! String
let downloadURL = rest.childSnapshot(forPath: "downloadURL").value as! String
let uid = rest.childSnapshot(forPath: "uid").value as! String
let pathURL = rest.childSnapshot(forPath: "pathURL").value as! String
let downloadURLRef = storage.reference(forURL: downloadURL)
let newTempAlias = tempAlias(name, downloadURL, pathURL)
tempAliasArray.append(newTempAlias)
}
group.leave()
}
})
}
func getAvaImages() {
for index in tempAliasArray{
avaGroup.enter()
let avaItem = DispatchWorkItem {
let avaURLRef = storage.reference(forURL: index.1)
avaURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
if (error == nil) {
print("success!")
let picData = UIImage(data:data!)
avaImageArray.append(picData!)
} else {
print(error?.localizedDescription)
}
print("we left getAvaImages()")
avaGroup.leave()
}
}
backgroundQueue.async(execute: avaItem)
}
}
func getImages() {
for index in tempAliasArray{
imageGroup.enter()
let imageItem = DispatchWorkItem {
let downloadURLRef = storage.reference(forURL: index.1)
downloadURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
if (error == nil) {
let picData = UIImage(data:data!)
imageArray.append(picData!)
} else {
print(error?.localizedDescription)
}
print("we left getImages()")
imageGroup.leave()
}
}
backgroundQueue.async(execute: imageItem)
}
}
backgroundQueue.sync(execute: workItem)
group.notify(queue: DispatchQueue.main, execute: {
print("group.notify is done")
getImages()
})
imageGroup.notify(queue: DispatchQueue.main, execute: {
print("images done")
getAvaImages()
})
avaGroup.notify(queue: DispatchQueue.main, execute: {
print("all is done")
})
}
您在 imageGroup
中没有任何内容时调用 imageGroup.notify
,因此它会立即通知。同样,avaGroup
会立即通知,因为在您调用它时它是空的。
但是我不明白所有的间接寻址和分组以及三个数组。为什么在处理每张图片之前必须等待所有图片下载?为什么不直接在原始循环中为一个元素启动下一步呢?像这样:
var allTheResults = []
group.enter() // Enter once for the top-level
kickOffAsyncWithCompletion { resultList in
for item in resultList {
let resultThing = doSomeStuffToSetupNextLevel()
group.enter() // Enter once per thing we iterate over
kickOffNestedAsync(with: resultThing, completion: { result in
let finalResult = computeFinalResult(fromResult: result)
allTheResults.append(finalResult)
group.leave() // leave once per thing we iterate over
})
}
group.leave() // leave once for the top level
}
group.notify { doThing(withFinalResults: allTheResults) }
如果您想协调一组操作的端点,您希望所有这些操作都与同一个组一起工作,而不是每个操作单独的组。