Swift DispatchQueue.main.asyncAfter未延迟
我的DispatchQueue.main.asyncAfter执行块未等待执行 我写了一个MacOS单视图应用程序。(代码12.0.1(12A7300))。它有一个for循环,调用从我的服务器下载内容的函数。我想限制这些请求。我正在尝试使用Swift DispatchQueue.main.asyncAfter未延迟,swift,grand-central-dispatch,dispatch-async,Swift,Grand Central Dispatch,Dispatch Async,我的DispatchQueue.main.asyncAfter执行块未等待执行 我写了一个MacOS单视图应用程序。(代码12.0.1(12A7300))。它有一个for循环,调用从我的服务器下载内容的函数。我想限制这些请求。我正在尝试使用DispatchQueue.main.asyncAfter。但是for循环中的所有调用都是立即同时进行的。这是我的密码: func fetchDocuments() { for index in 651...660 { let docN
DispatchQueue.main.asyncAfter
。但是for循环中的所有调用都是立即同时进行的。这是我的密码:
func fetchDocuments() {
for index in 651...660 {
let docNumber = String(index)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print(Date())
self.fetchDocument(byNumber: docNumber)
}
}
}
当我运行此代码时,我在控制台上得到以下输出:
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
2020-10-05 03:27:09 +0000
我正在从Xcode运行这段代码并观察控制台
任何帮助都将不胜感激。'DispatchQueue.main.asyncAfter'是一个异步进程。在这里,您已经为每个语句编写了“.now()+2”。但是循环执行的时间非常短。因此,循环中的每一条语句都需要2秒的时间 请尝试下面的代码
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fetchDocuments()
}
func fetchDocuments() {
var count = 0
for index in 651...660 {
let docNumber = String(index)
DispatchQueue.main.asyncAfter(deadline: .now() + (Double(count+1)*2.0)) {
print(Timestamp().printTimestamp())
self.fetchDocument(byNumber: docNumber)
}
count += 1
}
}
func fetchDocument(byNumber: String) {
print("Hello World")
}
}
class Timestamp {
lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS "
return formatter
}()
func printTimestamp() {
print(dateFormatter.string(from: Date()))
}
}
输出:
2020-10-05 10:41:18.473
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.475
()
Hello World
2020-10-05 10:41:18.476
()
Hello World
2020-10-05 10:41:18.476
()
Hello World
2020-10-05 10:41:18.476
()
Hello World
对
asyncAfter
的调用会立即返回,这意味着当您加速循环时,所有这些迭代从现在起将有效地触发2秒,而不是两秒
还有一些次要问题,当您使用asyncAfter
时,如果对象被解除分配并且您想要停止该过程,则取消它们会有点繁琐。此外,如果您提前计划所有这些asyncAfter
,您将受到计时器合并的影响(当后一个计划的事件彼此之间的距离在10%以内时,计时器合并会显示出来;651…660的范围没有问题,但如果使用更大的范围,计时器合并会显示出来)
几种常见的解决方案包括:
func fetchDocuments<T: Sequence>(in sequence: T) where T.Element == Int {
guard let value = sequence.first(where: { _ in true }) else { return }
let docNumber = String(value)
fetchDocument(byNumber: docNumber)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
self?.fetchDocuments(in: sequence.dropFirst())
}
}
func fetchDocuments<T: Sequence>(in sequence: T) where T.Element == Int {
var documentNumbers = sequence.map { String($0) }
let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
guard
let self = self,
let documentNumber = documentNumbers.first
else {
timer.invalidate()
return
}
self.fetchDocument(byNumber: documentNumber)
documentNumbers.removeLast()
}
timer.fire() // if you don't want to wait 2 seconds for the first one to fire, go ahead and fire it manually
}
func fetchDocuments(按顺序:T),其中T.Element==Int{
var documentNumbers=sequence.map{String($0)}
让timer=timer.scheduledTimer(withTimeInterval:2,repeats:true){[weak self]timer in
警卫
让自我=自我,
让documentNumber=documentNumbers.first
否则{
timer.invalidate()
返回
}
self.fetchDocument(按编号:documentNumber)
documentNumbers.removeLast()
}
timer.fire()//如果您不想等待2秒钟第一个计时器启动,请继续手动启动
}
这两个(a)将在每次调用之间提供两秒的间隔,(b)消除计时器合并风险;和(c)将取消,如果您关闭所讨论的对象。它确实会延迟,但会将所有对象延迟2秒。在
for
循环中使用asyncAfter
,该问题已被多次询问和回答。你可能想搜索自己,但这里有一个类似的问题。如果你想限制请求,那么你可以在每次下载完成后调用“syncAfter”-但是如果你真正想的是一次下载一个文件,按顺序,然后,您只需在当前文件的完成处理程序中调用下载下一个文件,感谢您使用计时器和post将延迟乘以for循环的索引/计数,为我指明了正确的方向。我搜索了SO,但我没有使用正确的搜索词。
func fetchDocuments<T: Sequence>(in sequence: T) where T.Element == Int {
var documentNumbers = sequence.map { String($0) }
let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
guard
let self = self,
let documentNumber = documentNumbers.first
else {
timer.invalidate()
return
}
self.fetchDocument(byNumber: documentNumber)
documentNumbers.removeLast()
}
timer.fire() // if you don't want to wait 2 seconds for the first one to fire, go ahead and fire it manually
}