Swift中TableViewController进度条不实时显示问题求助
Hey there, let's tackle this problem head-on—you're running into two key issues here: the progress bar only showing up after calculations finish, and that main thread warning. Let's break down why this is happening and how to fix it:
1. Your Calculations Are Blocking the Main Thread
If your doCalculation method is running on the main thread, that loop of computation is hogging all the main thread's resources. iOS can't update the UI (like adding your progress bar) until the main thread is free, which is why you only see the bar after calculations are done.
Fix: Move Calculations to a Background Thread
Wrap your computation logic in a background dispatch queue so it doesn't block the UI. Here's how to update your doCalculation method:
func doCalculation() { // Use a background queue for heavy computation DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } // Replace with your actual loop logic let totalCalculations = 100 // Example total steps for currentStep in 0..<totalCalculations { // Perform your calculation here // Calculate progress percentage and send it via notification let progress = Float(currentStep) / Float(totalCalculations) NotificationCenter.default.post( name: .return_progress, object: progress // Pass the progress value instead of self ) // Optional: If calculations are too fast, add a tiny delay to see the progress update // Thread.sleep(forTimeInterval: 0.01) } // Once done, switch back to main thread for any final UI cleanup DispatchQueue.main.async { // e.g., Hide the progress bar or show a completion message } } }
2. UI Operations Must Run on the Main Thread
The warning UIView.addSubview(_:) must be used from main thread only tells you exactly what's wrong: your showProgress method is being called from a background thread (since the notification is posted from the background calculation thread). iOS strictly requires all UI updates to happen on the main thread.
Fix: Force UI Updates to Run on the Main Thread
Update your showProgress method to wrap all UI code in DispatchQueue.main.async:
@objc func showProgress(notification: Notification) { DispatchQueue.main.async { [weak self] in guard let self = self else { return } // Add the progress bar if it's not already in the view hierarchy if !self.container_elementProperty.subviews.contains(where: { $0 is ProgressBarView }) { self.container_elementProperty.addSubview(self.progressBar) // Replace with your ProgressBarView instance // Set up constraints/frame for your progress bar here if needed } // Update the progress bar's value if we received progress data if let progress = notification.object as? Float { self.progressBar.progress = progress // Assuming your ProgressBarView has a `progress` property } } }
Bonus: Pass Progress Data Instead of self
Notice we changed the notification's object to pass the actual progress value instead of self. This lets you update the progress bar's value in real-time, not just show that calculations are running. Make sure your ProgressBarView has a property to accept this progress value (like a progress float that updates the bar's width or fill).
Key Takeaways
- Heavy work belongs in the background: Never run long calculations on the main thread—it freezes the UI.
- UI work belongs on the main thread: Always wrap UI updates in
DispatchQueue.main.asyncif there's any chance they're being called from a background thread. - Pass meaningful data via notifications: Sending progress values instead of just a signal lets you build a truly real-time progress bar.
内容的提问来源于stack exchange,提问作者Xin Lok

