Swift闭包完成处理:异步请求下UILabel隐藏逻辑实现问题
Got it, let's break this down. The core issue here is that your synchronous shouldHideLabel() function is trying to wait on an asynchronous network request—and that's a big no-no in iOS. Blocking the main thread (where UI code runs) will freeze your app, frustrate users, and even risk getting terminated by the system Watchdog.
Let's fix this with two practical, Apple-recommended approaches depending on your deployment target:
Option 1: Use Closure Callbacks (Compatible with iOS 13+)
If you need to support older iOS versions, refactor your functions to use completion closures instead of synchronous return values.
First, update your network request function to pass its result via a closure:
func webRequestDataIsValid(completion: @escaping (Bool) -> Void) { // Replace with your actual network request logic URLSession.shared.dataTask(with: yourRequestURL) { data, response, error in guard let data = data, error == nil else { completion(false) // Fallback to invalid if request fails return } // Parse your data here to get the `isValid` value let parsedResponse = try? JSONDecoder().decode(YourResponseModel.self, from: data) let isValid = parsedResponse?.isValid ?? false completion(isValid) }.resume() }
Then, refactor shouldHideLabel() to use a closure instead of returning a Bool directly:
func shouldHideLabel(completion: @escaping (Bool) -> Void) { webRequestDataIsValid { isValid in // Apply your actual hiding logic here // Example: Hide the label if the data is NOT valid let shouldHide = !isValid completion(shouldHide) } }
When you need to update the label, call it like this (remember to switch back to the main thread for UI updates):
shouldHideLabel { shouldHide in DispatchQueue.main.async { yourLabel.isHidden = shouldHide } }
Option 2: Use Swift Concurrency (iOS 15+/macOS 12+)
If you're targeting newer OS versions, Swift's async/await makes asynchronous code much cleaner and easier to read.
First, convert your network request to an async function:
func webRequestDataIsValid() async -> Bool { do { let (data, _) = try await URLSession.shared.data(from: yourRequestURL) let parsedResponse = try JSONDecoder().decode(YourResponseModel.self, from: data) return parsedResponse.isValid } catch { print("Network request failed: \(error)") return false // Fallback on failure } }
Then, update shouldHideLabel() to be async as well:
func shouldHideLabel() async -> Bool { let isValid = await webRequestDataIsValid() // Apply your hiding logic here return !isValid // Example logic }
To use this, call it from an async context (like a Task):
Task { let shouldHide = await shouldHideLabel() DispatchQueue.main.async { yourLabel.isHidden = shouldHide } }
Important Note: Don't Block the Main Thread!
Whatever you do, avoid using DispatchSemaphore or similar tools to "wait" for the async request in your original synchronous shouldHideLabel() function. This will block the main thread, freeze your UI, and likely get your app killed by the system's Watchdog process. Always handle asynchronous operations with callbacks or async/await instead.
内容的提问来源于stack exchange,提问作者Logan

