完成块中的函数从未执行,请求排查iOS代码执行异常问题
Hey there, let's walk through the most likely reasons your completion block never runs, and how to fix them step by step:
1. Your DataRequest.getDataTree Fails to Call the Completion Block in All Scenarios
This is the most common culprit. If your Alamofire request hits an error (network drop, invalid URL, server 4xx/5xx response) but you only trigger the completion block on success, the block will never fire.
Check your getDataTree implementation to ensure it invokes the completion handler every time, even when the request fails:
func getDataTree(handler: RequestHandler, completion: @escaping (DataTree?) -> Void) { AF.request("your-api-endpoint") .validate() // Marks HTTP errors (4xx/5xx) as request failures .responseJSON { response in switch response.result { case .success(let json): // Parse your DataTree from the JSON response let dataTree = DataTree(from: json) completion(dataTree) case .failure(let error): print("Request failed: \(error.localizedDescription)") // Critical: Call completion even when passing nil for errors completion(nil) } } }
2. Circular References Are Blocking the Closure Execution
If you're capturing strong references to self (your RequestHandler instance) or view (the ViewController) in the closure, you might create a retain cycle that keeps objects alive but prevents the closure from executing properly.
Fix this by using weak references in the closure to break cycles:
func getData(view: ViewController) { let dataRequest = DataRequest() // Capture a weak reference to RequestHandler to avoid cycles weak var weakHandler = self dataRequest.getDataTree(handler: weakHandler) { [weak view] response in // Unwrap the weak view to avoid accessing a deallocated object guard let safeView = view else { print("ViewController was deallocated before request completed") return } safeView.saveData(dataTree: response) } }
Also confirm that ViewController doesn't hold a strong reference to RequestHandler while RequestHandler holds a strong reference back—this creates a cycle that can stall closure execution.
3. The ViewController Is Deallocated Before the Request Finishes
If the user navigates away from the ViewController (e.g., pops it from a navigation stack, dismisses it) before the request completes, the view instance might be released. A strong reference in the closure would cause a memory leak, while a weak reference might lead the closure to skip execution when it detects view is nil.
To debug this, add a deinit method to your ViewController to check if it's being released early:
deinit { print("ViewController deallocated") }
If you see this log before the request should finish, consider canceling the request in viewWillDisappear to avoid unnecessary network activity.
4. The Network Request Isn't Being Sent At All
Double-check your Alamofire request configuration:
- Verify the API URL is correct (no typos, uses the right scheme: http/https)
- Ensure your app has network permissions (add
NSAppTransportSecurityexceptions if using non-HTTPS URLs) - Add Alamofire's debug logging to track the request lifecycle:
AF.request("your-api-endpoint") .debugLog() // Prints detailed request/response logs to the console .responseJSON { /* ... */ }
内容的提问来源于stack exchange,提问作者Zahikusa

