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

如何避免子ViewController内存泄漏?两种场景下的正确处理方式

Hey there! Let's break down how to handle memory management for both your static (ViewController2 via Storyboard Container View) and dynamic (ViewController3 added via code) child view controllers to avoid those pesky memory leaks. Here's a step-by-step breakdown for each scenario:

Static Child ViewController (ViewController2 via Storyboard Container View)

First, let's clarify the built-in relationship here: When you use a Storyboard Container View, UIKit automatically sets up a parent-child relationship between your main ViewController1 and ViewController2. The system already holds a strong reference to ViewController2 in ViewController1's children array—so you don't need to add another strong reference yourself.

The Fix: Use a Weak Reference for ViewController2

If you need to keep a reference to ViewController2 in ViewController1 for later access, always use a weak variable to avoid creating a retain cycle. Also, if ViewController2 needs a reference back to ViewController1, make sure that reference is weak too.

Example code for ViewController1:

// Inside ViewController1
weak var viewController2: ViewController2?

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let childVC = segue.destination as? ViewController2 {
        viewController2 = childVC
        // Pass a weak reference of ViewController1 to ViewController2 if needed
        childVC.parentVC = self // In ViewController2, declare this as `weak var parentVC: ViewController1?`
    }
}

Why This Works:

  • UIKit's children array already maintains a strong hold on ViewController2, so your weak reference is enough to access it when needed.
  • The weak back-reference from ViewController2 to ViewController1 ensures there's no circular strong reference that would prevent both VCs from being deallocated.
Dynamic Child ViewController (ViewController3 Added via Code)

When adding a child VC programmatically, you're responsible for managing the full parent-child lifecycle and its references. Here's how to do it right:

Step 1: Use a Strong Reference (If Needed)

If you need to access ViewController3 after adding it, store it in a strong variable in ViewController1—but you must explicitly clean it up when it's no longer needed.

Step 2: Follow the Full Child VC Lifecycle

Always call the required parent-child methods to ensure UIKit properly manages the VC's lifecycle, and then break the strong reference when done.

Example code for ViewController1:

// Inside ViewController1
var viewController3: ViewController3?

func addDynamicChildVC() {
    let childVC = ViewController3()
    // Establish parent-child relationship
    addChild(childVC)
    // Add the child's view to your hierarchy
    childVC.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 200)
    view.addSubview(childVC.view)
    // Finalize the relationship
    childVC.didMove(toParent: self)
    
    viewController3 = childVC
    // Again, pass a weak reference if the child needs to talk back
    childVC.parentVC = self // In ViewController3, this is `weak var parentVC: ViewController1?`
}

// Call this when you no longer need ViewController3 (e.g., on screen dismiss, or parent VC deinit)
func removeDynamicChildVC() {
    guard let childVC = viewController3 else { return }
    // Start the removal lifecycle
    childVC.willMove(toParent: nil)
    // Remove the view from the hierarchy
    childVC.view.removeFromSuperview()
    // Finalize removal from parent
    childVC.removeFromParent()
    // Break the strong reference to allow deallocation
    viewController3 = nil
}

// Always clean up in deinit to catch cases where removeDynamicChildVC wasn't called
deinit {
    removeDynamicChildVC()
}

Key Notes:

  • Skipping any of the parent-child lifecycle methods (addChild, didMove(toParent:), etc.) can lead to unexpected memory issues, as UIKit won't properly manage the child VC's state.
  • Setting viewController3 = nil is critical—it breaks the strong reference chain, allowing both the child and parent to be deallocated when they're no longer needed.
General Best Practices
  • Avoid Bidirectional Strong References: Never have both parent and child holding strong references to each other—this creates a retain cycle that will leak memory indefinitely.
  • Use Xcode's Memory Graph Debugger: If you suspect a leak, use this tool to inspect the reference chain of your view controllers and spot any unexpected strong holds.
  • Keep Child VCs Self-Contained: Minimize the need for parent-child references where possible—use delegation with weak delegates, or closure-based callbacks with [weak self] capture lists to avoid unnecessary references.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:02:50