You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 13:39:00