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

使用Alamofire请求数据时,未完成请求销毁ViewController导致其无法释放

Why Your ViewController Isn't Releasing & How to Fix It

Hey Anna, the issue you're facing is a classic strong reference cycle (memory leak) caused by how your Alamofire request's closure captures self. Let's break this down and fix it step by step:

The Root Cause

When you use Alamofire.request().responseJSON, the closure you pass in automatically captures a strong reference to self (since you're accessing self.arrData, self.tbvData, etc.). Even after you dismiss the ViewController, the ongoing network request keeps that strong reference alive—so ARC can't deallocate the ViewController from memory.

On top of that, I noticed a small logic error in your code: you're trying to process data when an error exists, which is backwards! We'll fix that too.

Fix 1: Break the Reference Cycle with Weak Self

The simplest fix is to use a weak reference to self in the closure. This tells Swift not to keep a strong hold on the ViewController, allowing it to be released even if the request is still running. We'll also add a guard check to make sure the ViewController still exists before updating the UI (no point in reloading a table view that's already gone!).

Here's the revised code:

func fetchingDataFromServer(url: String, completed: @escaping (Error?) -> Void) {
    Alamofire.request(url)
        .responseJSON { [weak self] response in // Capture weak self here
            // Make sure self still exists before proceeding
            guard let strongSelf = self else {
                completed(nil) // ViewController is gone—finish the callback
                return
            }
            
            if let result = response.result.value as? [[String: String]] {
                if let error = response.error {
                    // Error occurred: pass it to the completion handler
                    completed(error)
                } else {
                    // No error: process data and update UI
                    strongSelf.arrData = strongSelf.pasteData(result)
                    strongSelf.tbvData.reloadData()
                    completed(nil)
                }
            } else {
                // Data format doesn't match what we expected
                let formatError = NSError(domain: "DataMismatch", code: -1, userInfo: [
                    NSLocalizedDescriptionKey: "Server returned unexpected data format"
                ])
                completed(formatError)
            }
        }
}

Fix 2: Cancel the Request When the ViewController is Dismissed

For extra safety (and to save network resources), you can cancel the ongoing request when the ViewController is about to be deallocated. This ensures the closure doesn't run at all once the ViewController is gone.

First, store a reference to the request in your ViewController:

class YourViewController: UIViewController {
    // Hold a reference to the ongoing request
    private var activeDataRequest: DataRequest?

    func fetchingDataFromServer(url: String, completed: @escaping (Error?) -> Void) {
        // Save the request reference
        activeDataRequest = Alamofire.request(url)
            .responseJSON { [weak self] response in
                guard let strongSelf = self else {
                    completed(nil)
                    return
                }
                
                // Same processing logic as above...
                if let result = response.result.value as? [[String: String]] {
                    if let error = response.error {
                        completed(error)
                    } else {
                        strongSelf.arrData = strongSelf.pasteData(result)
                        strongSelf.tbvData.reloadData()
                        completed(nil)
                    }
                } else {
                    let formatError = NSError(domain: "DataMismatch", code: -1, userInfo: [
                        NSLocalizedDescriptionKey: "Server returned unexpected data format"
                    ])
                    completed(formatError)
                }
                
                // Clear the request reference once done
                strongSelf.activeDataRequest = nil
            }
    }

    // Cancel the request when the ViewController is deallocated
    deinit {
        activeDataRequest?.cancel()
        print("ViewController successfully deallocated!") // Use this to verify the fix
    }
}

How to Verify the Fix

You can use Xcode's Memory Graph Debugger (the icon that looks like three circles connected by lines) to check if the ViewController is being released. After dismissing it, if it doesn't show up in the memory graph, you've fixed the leak!

内容的提问来源于stack exchange,提问作者Anna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:08:44