【发布时间】:2022-01-16 00:03:55
【问题描述】:
我想知道是否有人可以就如何在 Swift 的一个特别密集的功能(在主线程上)期间“强制”更新 UI 提供建议。
解释一下:我正在尝试向我的应用程序添加“导入”功能,这将允许用户从备份文件中导入项目(可以是 1 到 1,000,000 条记录之间的任何内容,例如,取决于他们的大小备份)保存到应用程序的 CodeData 数据库。此函数使用“for in”循环(循环遍历备份文件中的每条记录),并且该循环中的每个“for”,该函数都会向委托(ViewController)发送一条消息以更新其 UIProgressBar 进度因此用户可以在屏幕上看到实时进度。我通常会尝试将此密集功能发送到后台线程,并在主线程上单独更新 UI……但这不是一个选项,因为在 CoreData 上下文中创建这些项目必须在主线程上完成(根据当我最初尝试在后台线程上执行 Swift 时出现错误/崩溃),因此我认为这会导致 UI “冻结”而不是在屏幕上实时更新。
代码的简化版本是:
class CoreDataManager {
var delegate: ProgressProtocol?
// (dummy) backup file array for purpose of this example, which could contain 100,000's of items
let backUp = [BackUpItem]()
// intensive function containing 'for in' loop
func processBackUpAndSaveData() {
let totalItems: Float = Float(backUp.count)
var step: Float = 0
for backUpItem in backUp {
// calculate Progress and tell delegate to update the UIProgressView
step += 1
let calculatedProgress = step / totalItems
delegate?.updateProgressBar(progress: calculatedProgress)
// Create the item in CoreData context (which must be done on main thread)
let savedItem = (context: context)
}
// loop is complete, so save the CoreData context
try! context.save()
}
}
// Meanwhile... in the delegate (ViewController) which updates the UIProgressView
class ViewController: UIViewController, ProgressProtocol {
let progressBar = UIProgressView()
// Delegate function which updates the progress bar
func updateProgressBar(progress: Float) {
// Print statement, which shows up correctly in the console during the intensive task
print("Progress being updated to \(progress)")
// Update to the progressBar is instructed, but isn't reflected on the simulator
progressBar.setProgress(progress, animated: false)
}
}
需要注意的重要一点:上述代码中的 print 语句运行良好/符合预期,即在整个较长的“for in”循环中(可能需要一两分钟),控制台连续显示所有打印语句(显示增加的进度值),所以我知道委托 'updateProgressBar' 函数肯定是正确触发的,但是屏幕本身上的进度条 根本没有更新 /没有改变……我假设这是因为 UI 被冻结并且没有“时间”(因为需要一个更好的词)来反映考虑到主要功能运行的强度的更新进度。
我对编码比较陌生,所以如果我要求澄清任何回复,请提前道歉,因为这对我来说是新的。如果相关,我使用 Storyboards(而不是 SwiftUI)。
只是真的在寻找关于是否有任何(相对简单的)路线来解决这个问题的任何建议/提示,并且基本上“强制”在这个密集的任务期间更新 UI。
【问题讨论】:
-
我应该补充一点,为了这篇文章,上面的代码只是作为 example 编写的......所以 UIProgressView 没有 IBOutlet 的事实不是一个问题...对象都与 real 代码中的情节提要正确连接...当然,当不运行这个密集的“for in”循环时,我可以更新应用程序中的进度条
-
您需要将密集工作移出主队列。 developer.apple.com/documentation/coredata/…
-
谢谢 Paulw11 - 在这种情况下,这肯定是队列/线程管理的事情 - 非常感谢您发送这些链接...非常感谢您的意见
标签: ios swift multithreading user-interface