在以下代码中,是否可以安全地附加到数组?保证维护订单吗?
let processedData: [SomeType] = []
let dispatchGroup = DispatchGroup()
for _ in 0..<N {
dispatchGroup.enter()
startSomeAsyncTaskXYZ { (data, error) in
// handle error and process data
// add processed data to an array
processedData.append(..)
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
// update UI
}
在保留所需的异步性质和预期订购时坚持使用DispatchGroup
,使您的数组成为一系列选项,并以任何顺序填充任务:
var processedData: [SomeType?] = Array(repeating: nil, count: N)
let dispatchGroup = DispatchGroup()
for idx in 0..<N {
dispatchGroup.enter()
startSomeAsyncTaskXYZ { (data, error) in
// Ensure we always .leave() after we're done
// handling the completion of the task
defer { dispatchGroup.leave() }
guard let data = data,
error == nil else {
// TODO: Actual error handling
return
}
// This needs to be .sync now (not .async) to ensure
// the deferred dispatchGroup.leave() is not called
// until *after* we've updated the array
DispatchQueue.main.sync {
processedData[idx] = SomeType(data: data)
}
}
}
dispatchGroup.notify(queue: .main) {
// update UI
}
DispatchGroup
与执行顺序无关。这仅仅是跟踪任务组完成的一种方式。
该组的组成任务是否运行async
或sync
,以及按什么顺序运行,完全取决于您如何使用DispatchQueue
s。
刚刚使用我的应用程序进行了此操作。我有一些需要按顺序完成的异步任务。完成此操作的最佳方法是通过dispatchGroup()
和semaphore()
。
基本思想是dispatchGroup
没有以特定顺序获取数据,但是如果需要,semaphore
的特定顺序是。
这是一个很好的视频,可以证明它:https://www.youtube.com/watch?v=6rjn_ecd1xm& ab_channel = letsbuildthatapp
一些示例代码看起来像这样:
let dispatchQueue = DispatchQueue.global(qos: .userInitiated)
let dispatchGroup = DispatchGroup()
let semaphore = DispatchSemaphore(value: 0)
override func viewDidLoad() {
dispatchQueue.async {
// --------------
// Family members
// --------------
// Get members and household information first (esp. payday time and time zone), then everything else
self.dispatchGroup.enter()
MPUser.loadFamilyMembers {
print("We got us some fambly members!")
self.dispatchGroup.leave()
self.semaphore.signal()
}
// ^^^ Wait for above code to finish ('signal') before moving on (in other words, get users first)
self.semaphore.wait()
// --------------
// Household info
// --------------
self.dispatchGroup.enter()
FamilyData.observeHouseholdInformation {
self.dispatchGroup.leave()
self.semaphore.signal()
}
// ^^^ Wait for above code to finish ('signal') before moving on (in other words, get users first, then household info)
self.semaphore.wait()
// ---------------
// Everything else
// ---------------
self.dispatchGroup.enter()
Setup.observeProgress {
self.dispatchGroup.leave()
}
self.dispatchGroup.enter()
OutsideIncome.observeUserOutsideIncomeBudget {
self.dispatchGroup.leave()
}
self.dispatchGroup.enter()
MPUser.observeCurrentEarnings {
self.dispatchGroup.leave()
}
self.dispatchGroup.notify(queue: .main) {
let end = Date()
print("nAll functions completed in (end.timeIntervalSince(self.start!).rounded(toPlaces: 2)) seconds!n")
self.sendUserToCorrectPage()
}
}
}