Swift中如何从另一类更新ViewController视图控制器的UI界面
实现方案
第一步:在Task.swift中定义进度回调闭包
给任务类添加进度回调属性,任务执行过程中实时抛出进度值和状态文本,所有回调主动切换到主队列,避免UI更新异常。
import Foundation class TaskManager { // 进度回调参数:(当前进度0~1, 状态文本) var progressHandler: ((Double, String) -> Void)? // 任务完成回调 var completionHandler: (() -> Void)? func startBackgroundTask() { DispatchQueue.global().async { [weak self] in // 模拟总任务共100步 let totalStep = 100 for step in 0...totalStep { Thread.sleep(forTimeInterval: 0.05) // 模拟任务执行耗时 let currentProgress = Double(step)/Double(totalStep) let statusText = "当前执行进度:\(step)/\(totalStep)" // 切回主队列回调给UI层 DispatchQueue.main.async { self?.progressHandler?(currentProgress, statusText) } } // 任务执行完成回调 DispatchQueue.main.async { self?.completionHandler?() } } } }
第二步:在ViewController中绑定回调更新UI
在按钮点击事件中初始化任务实例,绑定进度回调和完成回调,直接在回调内更新progressView和label即可。
import UIKit class ViewController: UIViewController { @IBOutlet weak var progressView: UIProgressView! @IBOutlet weak var statusLabel: UILabel! @IBOutlet weak var startButton: UIButton! // 持有任务实例避免中途被释放 private var taskManager: TaskManager? @IBAction func startButtonTapped(_ sender: UIButton) { // 点击后先禁用按钮避免重复触发 startButton.isEnabled = false statusLabel.text = "任务准备中..." progressView.progress = 0 // 初始化任务并绑定回调 taskManager = TaskManager() taskManager?.progressHandler = { [weak self] progress, status in guard let self = self else { return } self.progressView.progress = Float(progress) self.statusLabel.text = status } taskManager?.completionHandler = { [weak self] in guard let self = self else { return } self.statusLabel.text = "任务执行完成" self.startButton.isEnabled = true } // 启动后台任务 taskManager?.startBackgroundTask() } }
注意事项
- 所有UI更新逻辑必须在主队列执行,后台队列直接更新UI会导致界面卡顿甚至崩溃,上述代码已在Task层统一处理了线程切换,UI层无需重复处理
- 任务实例需要在ViewController中强持有,否则执行到一半实例被释放会无法收到回调
- 回调中添加
[weak self]可避免循环引用导致的内存泄漏
内容的提问来源于stack exchange,提问作者Hamza Mahmood
相关产品推荐
相关产品推荐

