侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Swift 中的内存管理与循环引用陷阱

2025-12-12 / 0 评论 / 4 阅读

题目

Swift 中的内存管理与循环引用陷阱

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

ARC原理,循环引用解决,weak与unowned区别,闭包捕获列表

快速回答

在Swift中处理循环引用的核心要点:

  • 使用weak打破父-子对象间的循环引用(子对象引用父对象时)
  • 使用unowned当引用对象生命周期相同或更长时(需确保不会访问已释放对象)
  • 在闭包中使用捕获列表[weak self][unowned self]避免闭包强持有
  • 对于值类型(如struct)无需担心循环引用
## 解析

原理说明

Swift使用自动引用计数(ARC)管理内存。当两个或多个对象相互强引用时形成循环引用,导致内存泄漏。解决方案:

  • weak:允许引用变为nil的弱引用(自动置nil)
  • unowned:假定引用始终有效,访问已释放对象会触发运行时崩溃
  • 闭包捕获列表:显式声明闭包捕获的引用关系

代码示例

class Parent {
    var child: Child?
    deinit { print("Parent deallocated") }
}

class Child {
    // 正确:weak打破循环
    weak var parent: Parent? 
    // 危险:unowned需确保parent生命周期更长
    // unowned let parent: Parent 

    var closure: (() -> Void)?

    init(parent: Parent) {
        self.parent = parent

        // 闭包循环引用示例
        closure = { [weak self] in
            // 必须使用weak self或unowned self
            print(self?.parent)
        }
    }

    deinit { print("Child deallocated") }
}

// 测试
var parent: Parent? = Parent()
parent?.child = Child(parent: parent!)
parent = nil // 正确释放

最佳实践

  • 优先使用weak避免野指针崩溃
  • 仅当对象生命周期严格长于当前对象时使用unowned
  • 闭包中强制使用捕获列表声明引用关系
  • 使用weak后需处理可选类型(self?

常见错误

  • 在闭包中直接使用self导致循环引用
  • 错误使用unowned访问已释放对象
  • 忽略[weak self]后对self?的可选处理
  • 未注意协议声明中的class约束导致值类型循环引用误判

扩展知识

  • 闭包捕获原理:闭包是引用类型,默认强捕获所有外部变量
  • weak vs unowned性能unowned无额外开销,但风险更高
  • 调试技巧:使用Xcode Memory Graph Debugger检测循环引用
  • 新特性:Swift 5.0引入@unknownweakable提案讨论更安全的unowned