Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`
Posted
技术标签:
【中文标题】Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`【英文标题】:Swift 5: I Am Unable to Get My UITableView To Update In A Timely Manor (Using both `DispatchQueue.global().sync` and `DispatchQueue.main.async` 【发布时间】:2021-12-04 15:19:10 【问题描述】:Swift 5:我无法及时更新我的 UITableView(同时使用 DispatchQueue.global().sync
和 DispatchQueue.main.async
简而言之:
我有一个简单的for index in 1…20
循环可以做一些“事情”。
在 20 次迭代中的每一次结束时,我都会将一个新元素附加到作为我的 UITableView 的数据源的数组中。
我只是想让 UITableView 在开始下一次循环迭代之前更新显示。
真的有这么多要问的吗?哈哈
我试过把所有的“工作”放在后台线程上,我什至用QoSClass.utility
创建了一个线程,不管我做什么......它完全忽略了所有出现的DispatchQueue.main.async
,直到整个函数完成.
我可以毫无问题地完成我的代码需要完成的工作。在这一点上,我面临的挑战是控制事情发生的顺序并让显示更新(并保持对用户的响应,目前不会这样做)。
编辑/更新:
使用下面的答案......如果我使用 .async
我会得到我想要的及时更新但我没有得到按顺序 1、2 的索引结果, 3 ... 20. 如果我使用 .sync
我得到了我想要的订单但没有更新。 如何让我的循环按顺序执行并在每个循环中显示一次 GET UPDATES?
我对这里的线程非常陌生,所以请慢慢输入。谢谢!
这是我非常精简的代码:
//
// 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 秒 ✅
再打印一个紫色行✅
这是我的 ACTUAL 控制台输出:
绿线,来自高优先级主线程,直到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????????????????????????????????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
【问题讨论】:
如果你真的不了解线程,并且如果你可以将你的应用程序限制在 ios 15 及更高版本,那么使用美妙的新 async/await 你会很多更快乐东西。 【参考方案1】:当用户点击按钮时,你就在主线程上;它正在处理那个按钮点击事件。
在处理该事件时,然后创建一个队列 @987654321@ 并使用 JimmysQue.sync ...
对其执行同步操作。
通过调用sync
,你是在说“我想在另一个队列上执行这个操作,但我也想(同步地)等到另一个队列完成。换句话说,你已经把 Main线程暂停,直到您发送到JimmysQue
的块完成。
运行该后台操作时,JimmysQue
调用 DispatchQueue.main.async
。您可能与此相关的概念模型是“向主事件事件循环发送一个事件,当没有其他事件正在处理时,它将运行此代码块。”
但请记住,主线程仍在处理您的点击事件!你暂停它直到JimmysQue
可以完成运行它的块。因此,在您的按钮处理程序完成并且您的按钮处理程序仍在等待您发送到JimmysQue
的其余活动之前,您已分派到主线程的东西不会运行。
我认为可以让您获得想要的效果的简单更改是使用async
而不是sync
将您的块发送到JimmysQue
。
验证块将被发送到后台运行。主线程不会等待它(按钮单击事件将完成,主线程将开始处理任何其他事件)。
然后,当JimmysQue
上的块完成验证时,它将使用DispatchQueue.main.async
发送块,以便在有空闲时间时在主线程上执行。
我...打字...这个...非常...慢...
这里有一个更精简的示例来演示一般流程。您可以将其粘贴到 Playground 中。尝试在.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()
您在 cmets 中询问有关订购完成结果的问题。这是一个例子:
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
分派到主队列,因此每个后台任务在完成之前等待主队列确认完成。
【讨论】:
谢谢‼️ 如果我使用.async
,我会及时获得我想要的更新,但是我没有按 1、2、3…20 的顺序获得索引结果。如果我使用 .sync
我得到了我想要的订单,但没有更新。如何让我的循环按顺序执行并获取更新以在每个循环中显示一次?并且感谢您慢慢打字!哈哈
您要做的第一件事是创建一个串行队列,以便您发送到队列的块一个接一个地执行。您调度的第二个块在第一个块完成之前不会执行。然后,您将对Dispatch.main
的调用更改为Dispatch.main.sync
。这样 background 线程每次都会暂停,直到主线程完成。
我添加了第二个代码示例来演示结果的排序。以上是关于Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`的主要内容,如果未能解决你的问题,请参考以下文章
iOS Swift:deleteRowsAtIndexPaths 崩溃 [重复]