问题
The task is to change the background color once a second. Was used "for in loop". For delay, a DispatchQueue was used. Everything seems to be fine, but it was noticed that after 10 iterations, the background color begins to change with a delay of 2 seconds, a little later in 3 seconds. The more iterations, the greater the delay. I displayed time in the console (seconds) to see how it changes. I see the results, but I do not understand what is wrong. I did the task through a timer, there were no problems, but I want to understand what is wrong with the DispatchQueue delay.
for i in 1...150 {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
self.view.backgroundColor = UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
print("\(ymd)")
ymd = self.myCalendar.dateComponents([.second], from: Date())
}
}
Console:
second: 21 isLeapMonth: false
second: 21 isLeapMonth: false
second: 22 isLeapMonth: false
second: 23 isLeapMonth: false
second: 24 isLeapMonth: false
second: 25 isLeapMonth: false
second: 26 isLeapMonth: false
second: 27 isLeapMonth: false
second: 28 isLeapMonth: false
second: 29 isLeapMonth: false
second: 30 isLeapMonth: false
second: 32 isLeapMonth: false
second: 33 isLeapMonth: false
second: 33 isLeapMonth: false
second: 35 isLeapMonth: false
second: 35 isLeapMonth: false
second: 37 isLeapMonth: false
second: 37 isLeapMonth: false
second: 39 isLeapMonth: false
second: 39 isLeapMonth: false
second: 41 isLeapMonth: false
second: 41 isLeapMonth: false
second: 44 isLeapMonth: false
second: 44 isLeapMonth: false
second: 44 isLeapMonth: false
second: 47 isLeapMonth: false
second: 47 isLeapMonth: false
second: 47 isLeapMonth: false
second: 50 isLeapMonth: false
second: 50 isLeapMonth: false
second: 50 isLeapMonth: false
second: 54 isLeapMonth: false
second: 54 isLeapMonth: false
second: 54 isLeapMonth: false
second: 57 isLeapMonth: false
second: 57 isLeapMonth: false
second: 57 isLeapMonth: false
second: 57 isLeapMonth: false
second: 1 isLeapMonth: false
second: 1 isLeapMonth: false
second: 1 isLeapMonth: false
second: 1 isLeapMonth: false
second: 6 isLeapMonth: false
second: 6 isLeapMonth: false
second: 6 isLeapMonth: false
second: 6 isLeapMonth: false
second: 6 isLeapMonth: false
second: 11 isLeapMonth: false
second: 11 isLeapMonth: false
second: 11 isLeapMonth: false
second: 11 isLeapMonth: false
second: 11 isLeapMonth: false
second: 17 isLeapMonth: false
second: 17 isLeapMonth: false
second: 17 isLeapMonth: false
second: 17 isLeapMonth: false
second: 17 isLeapMonth: false
回答1:
This is a result of “timer coalescing”, in which the “leeway” for the dispatched block is 10% of the delay, up to a max of one minute of leeway. (This is buried in the libdispatch code.) It’s a power saving feature to coalesce/group distant, independently scheduled tasks to run at the same time to avoid unnecessary spinning up the hardware too many times. The easiest way to avoid this coalescing is to use a repeating timer:
var counter = 0
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
counter += 1
guard let self = self, counter <= 150 else {
timer.invalidate()
return
}
self.view.backgroundColor = UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
let ymd = self.myCalendar.dateComponents([.second], from: Date())
print(ymd)
}
Note the use of the [weak self]
pattern, to avoid having the timer keep a persistent reference to the view controller. And with that guard
statement, we’ll invalidate
the timer if the view controller is dismissed.
BTW, if you want to make the color change less jarring, animate the change:
var counter = 0
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
counter += 1
guard let self = self, counter <= 150 else {
timer.invalidate()
return
}
UIView.animate(withDuration: 0.1) {
self.view.backgroundColor = UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
}
...
}
来源:https://stackoverflow.com/questions/61147543/using-delay-dispatchqueue-in-for-in-loop