I have the following code
func randomIndices(n: Int) -> [Int] {
var result: [Int] = []
var used: [Bool] = (0 ..< n).map { _ in false }
for _ in 0 ..< n {
var r = Int.random(in: 0 ..< n)
while used[r] {
r = (r + 1) % n
}
used[r] = true
result.append(r)
}
return result
}
func split<R>(array: [R], n: Int) -> [[R]] {
var result: [[R]] = (0 ..< n).map { _ in [] }
var index = 0
for item in array {
result[index].append(item)
index = (index + 1) % n
}
return result
}
func inParallell<R>(count: Int, n: Int = 4, function: (Int) -> R, progress: ((Double) -> Void)? = nil) -> [R] {
let indices = split(array: randomIndices(n: count), n: n)
var res: [R?] = .init(repeating: nil, count: count)
let lock = NSRecursiveLock()
var meter = 0.0, step = 1.0 / Double(count)
DispatchQueue.concurrentPerform(iterations: indices.count) { i in
for index in indices[i] {
let result = function(index)
lock.lock()
res[index] = result
meter += 1.0 / step
DispatchQueue.main.async {
print("inParallell meter (meter)")
progress?(meter)
}
lock.unlock()
}
}
DispatchQueue.main.async {
progress?(1)
}
return res.map({ $0! })
}
func waitSomeTime() {
var x = 0
for i in 0 ..< 1_000_000 {
x += i
}
}
struct InParallellTestView: View {
@State var progress = 0.0
var body: some View {
ProgressView(value: progress)
.onAppear {
let _ = inParallell(count: 10, function: { _ in
waitSomeTime()
}, progress: { p in progress = p })
}
}
}
The idea is that the progress bar should be updated while the code runs, but if I look at the printout it says “inParallell meter 100.0” repeated, ie all meter updates occur at the end. I’ve tried the whole ConcurrentPerform block in a “DispatchQueue.global(qos: .utility).sync” block but that dit not change the result.
I tried running the code and also changing the DispatchQueue.main.async to sync but that did not make a difference either. The result is that all updates to the progress bar occur after the computation is finished.