Swift 5:我无法及时更新我的 UITableView(同时使用 'DispatchQueue.global().s



Swift 5:我无法及时更新我的 UITableView (同时使用DispatchQueue.global().syncDispatchQueue.main.async

简而言之:

  • 我有一个简单的for index in 1…20循环,可以做一些"东西"。
  • 在 20 次迭代中的每次迭代结束时,我都会将一个新元素追加到作为 UITableView 数据源的数组中。
  • 我只是希望 UITableView 在开始循环的下一次迭代之前更新显示。
    • 真的有那么多要问的吗?大声笑

我尝试将所有"工作"放在后台线程上,我什至创建了一个带有QoSClass.utility线程,无论我做什么......它完全忽略所有出现的DispatchQueue.main.async,直到整个函数完成。

我可以毫无问题地完成我的代码需要完成的工作。 在这一点上,我的挑战是控制事情发生的顺序并让显示器更新(并保持对用户的响应,目前没有这样做)。

编辑/更新:

使用下面的答案...如果我使用.async我会得到我想要的及时更新,但我没有得到顺序 1、2、3 的索引结果......20. 如果我使用.sync我会得到我想要的订单,但没有更新。如何让我的循环按顺序执行并获取更新以在每个循环显示一次?

我对这里的线程非常陌生,所以请慢慢输入。 谢谢!

这是我非常精简的代码:

//
//  ValidateViewController.swift
//  MySpecialProject
//
//  Created by Jim Termini on 10/16/21.
//
import UIKit
import PDFKit
import UniformTypeIdentifiers
import CoreData
class ValidateViewController: UIViewController, PDFViewDelegate {
@IBOutlet weak var tableView: UITableView!
var statuses: [ValidationStatus] = []
//                                                            
//      START HERE: ViewDidLoad
//                                                            
override func viewDidLoad() {
super.viewDidLoad()
statuses = createStatusArray()
tableView.delegate = self
tableView.dataSource = self
}

//                                                            
//      Button Pressed — Start Validating the Document!!
//                                                            
@IBAction func startValidatIn(_ sender: Any) {
print("                                                            ")
print("                                                            ")
theMainThing()
print("                                                            ")
print("                                                            ")
}

//                                                            
//      theMainThing function called when button pushed.
//                                                            
func theMainThing() {
print("                                                            ")
print(pickedDocSourceFPnFURL ?? "No File Picked")

let openResults = openFile(pdfURLToSearch: pickedDocSourceFPnFURL!)
originalPDFDocument = openResults.0
metaPDFModifiedDate = openResults.1
var unaccountedPageCount = orginalDocumentPageCount

// Keep track of the total number of Forms found in the Document
var theFormCount = 0
let JimmyQoS: DispatchQoS.QoSClass = DispatchQoS.QoSClass.utility
let JimmysQue: DispatchQueue = DispatchQueue.global(qos: JimmyQoS)
var countOfFormsOfThisPageLength: Int = 0
var dummyVar: Int = 0

for index in 1...20 {
JimmysQue.sync {
print("                                                            ")
if index == 6 {
//
//  Do special case stuff when index = 6
//
} else if index == 1 {
//
//  Do special case stuff when index = 6
//
} else {
//
//  Do regular case stuff when index = 2 – 5, 7 – 20.
//
}
print("                                                            ")
print("The NEXT Line is "DispatchQueue.main.async" SHOULD see GREEN row NEXT!!")

DispatchQueue.main.async  {
print("      (Date())                                                      ")
print("Here I am ... INSIDE the main thread async.")
if countOfFormsOfThisPageLength > 0 {
let term = (countOfFormsOfThisPageLength > 1) ? "forms" : "form"
self.statuses.append((ValidationStatus(image: StatusIcon.allGood,  title: "Identified (countOfFormsOfThisPageLength) (term) of (index) pages each.", details: "Unaccounted for Pages: (dummyVar) of (self.orginalDocumentPageCount)")))
self.tableView.reloadData()
self.tableView.setNeedsDisplay()
}
print("This SHOULD be causing my display to update.")
print("      (Date())                                                      ")
}

print("      (Date())                                                      ")
print("Here I am ... about to sleep the global (background) thread for 5 seconds to ensure the TableView is updated and displayed properly.")
sleep(5)
print("And here I am ... 5 seconds later ... still no UIViewTable Update :-(")
print("      (Date())                                                      ")
}
}
}
}

这是应该发生的事情和应该发生的事情的演练......

  • 我按下"开始验证"按钮
  • 两行紫色/绿色印花 ✅
  • 调用theMainThing()函数 ✅
  • 一行红色/黄色打印 ✅
  • for index in 1…20循环开始 ✅
    • 黄线在每个循环✅的开头打印
    • 我的处理确实做了它应该做的事情 ✅
    • DispatchQueue.main.async块应该以更高的优先级执行更新UITableView之前,会打印一条红线。 ✅
    • 主 (UI) 线程应该启动并 ❌
      • 打印绿色行 ❌
      • 更新 UITableView/Display ❌
      • 打印第二个绿色行 ❌
    • 要给 UI 时间更新...我
      • 打印紫色行 ✅
      • 使后台队列休眠 5 秒钟 ✅
      • 打印另一个紫色行 ✅

这是我的实际控制台输出:

来自高优先级主线程的绿线直到for index in 1…20循环完成后 +theMainThing()函数完成后 +startValidatIn(_ sender: Any)函数完成后才会执行! !️






The NEXT Line is "DispatchQueue.main.async" SHOULD see GREEN row NEXT!!
2021-10-17 02:34:21 +0000                                                      
Here I am ... about to sleep the global (background) thread for 5 seconds
to ensure the TableView is updated and displayed properly.
And here I am ... 5 seconds later ... still no UIViewTable Update :-(
2021-10-17 02:34:26 +0000                                                      

-------------------------
18 Duplicate Sets Omitted
-------------------------



The NEXT Line is "DispatchQueue.main.async" SHOULD see GREEN row NEXT!!
2021-10-17 02:34:26 +0000                                                      
Here I am ... about to sleep the global (background) thread for 5 seconds
to ensure the TableView is updated and displayed properly.
And here I am ... 5 seconds later ... still no UIViewTable Update :-(
2021-10-17 02:34:31 +0000                                                      


2021-10-17 02:46:34 +0000                                                      
Here I am ... INSIDE the main thread async.
This SHOULD be causing my display to update.
2021-10-17 02:46:34 +0000                                                      
2021-10-17 02:46:34 +0000                                                      
Here I am ... INSIDE the main thread async.
This SHOULD be causing my display to update.
2021-10-17 02:46:34 +0000                                                      

这是我的控制台输出应该是

每条红线之后应该是高优先级主 UI 线程的绿线。






The NEXT Line is "DispatchQueue.main.async" SHOULD see GREEN row NEXT!!
2021-10-17 02:46:34 +0000                                                      
Here I am ... INSIDE the main thread async.
This SHOULD be causing my display to update.
2021-10-17 02:46:34 +0000                                                      
2021-10-17 02:34:21 +0000                                                      
Here I am ... about to sleep the global (background) thread for 5 seconds
to ensure the TableView is updated and displayed properly.
And here I am ... 5 seconds later ... still no UIViewTable Update :-(
2021-10-17 02:34:26 +0000                                                      


The NEXT Line is "DispatchQueue.main.async" SHOULD see GREEN row NEXT!!
2021-10-17 02:46:34 +0000                                                      
Here I am ... INSIDE the main thread async.
This SHOULD be causing my display to update.
2021-10-17 02:46:34 +0000                                                      
2021-10-17 02:34:26 +0000                                                      
Here I am ... about to sleep the global (background) thread for 5 seconds
to ensure the TableView is updated and displayed properly.
And here I am ... 5 seconds later ... still no UIViewTable Update :-(
2021-10-17 02:34:31 +0000                                                      


当用户单击按钮时,您位于主线程上;它正在处理该按钮单击事件。

在处理该事件时,然后创建一个队列JimmysQue并使用JimmysQue.sync { ... }对其执行同步操作。

通过调用sync您是在说"我想在另一个队列上执行此操作,但我也想(同步)等到另一个队列完成。 换句话说,您已将主线程置于暂停状态,直到您调度到JimmysQue的块完成。

运行该后台操作时,JimmysQue调用DispatchQueue.main.async。 您可能与此关联的概念模型是"将事件发送到主事件事件循环,该循环将在没有处理其他事件时运行此代码块。

但请记住,主线程仍在处理您的点击事件! 您暂停了它,直到JimmysQue可以完成运行其块。 因此,在按钮处理程序完成并且按钮处理程序仍在等待发送到JimmysQue的其余活动之前,已调度到主线程的内容不会运行。

我认为可以使您获得所追求的效果的简单更改是使用async而不是sync将块发送到JimmysQue

验证块将被发送出去在后台运行。主线程不会等待它(按钮单击事件将完成,主线程将关闭以处理任何其他事件)。

然后,当JimmysQue上的块完成验证时,它将使用DispatchQueue.main.async发送块,以便在它有一些空闲时间时在主线程上执行。

我... 打字...这。。。非常。。。慢慢。。。

下面是一个更精简的示例,用于演示常规流。 你可以把它粘贴到游乐场中。尝试将.utility队列上的呼叫从async更改为sync,以查看行为如何变化。

import Foundation
func theMainThing() {
print("Dispatching blocks from main thread")
for index in 1...20 {
DispatchQueue.global(qos: .utility).async {
// Sleep for a random amount of time to simulate a long
// running Action
sleep((1...5).randomElement()!)
DispatchQueue.main.async  {
print("The main thing's index number (index) completed")
}
}
}
print("The Main Thread has gone on to bigger and better things")
}
theMainThing()

在评论中,您询问了有关订购完成结果的问题。 下面是一个示例:

import Foundation
func theMainThing() {
print("Dispatching Async blocks from main thread")
let scottsQueue = DispatchQueue(label: "ValidationQueue", qos: .utility)
for index in 1...20 {
scottsQueue.async {
print("The starting item (index)")
// Sleep for a random amount of time to simulate a long
// running Action
sleep((1...5).randomElement()!)
DispatchQueue.main.sync {
print("The main thing's index number (index) completed")
}
}
}
print("The Main Thread has gone on to bigger and better things")
}
theMainThing()

请注意,我们将所有验证块放入串行队列中,以便严格按顺序执行它们。 每个块都使用sync调度到主队列,因此每个后台任务在完成之前等待主队列确认完成。

相关内容

  • 没有找到相关文章

最新更新