Skip to content

Swift 入门(19):内存管理

Swift 使用 ARC(Automatic Reference Counting) 自动管理内存,大多数情况下不需要手动释放对象。但理解其工作原理非常重要,尤其是避免循环引用。

1. ARC 的基本原理

  • 每个类实例都有一个 引用计数
  • 当引用 +1 时,实例保留。
  • 当引用变为 0 时,实例被销毁。
swift
class Person {
  let name: String
  init(name: String) { self.name = name }
  deinit { print("\(name) 被销毁") }
}

var p1: Person? = Person(name: "Tom")
p1 = nil // 引用计数归零,触发 deinit

2. 强引用(Strong Reference)

默认情况下,变量保存对象时会创建一个 强引用

swift
class Dog {}
var d1: Dog? = Dog()
var d2 = d1 // d1, d2 都是强引用

3. 循环引用问题

如果两个对象相互持有强引用,会导致 循环引用,对象无法释放。

swift
class Teacher {
  var student: Student?
  deinit { print("Teacher deinit") }
}

class Student {
  var teacher: Teacher?
  deinit { print("Student deinit") }
}

var t: Teacher? = Teacher()
var s: Student? = Student()

t?.student = s
s?.teacher = t

t = nil
s = nil
// ❌ Teacher 和 Student 都不会释放

4. 解决循环引用

4.1 弱引用(weak)

  • weak 修饰,引用不会增加计数。
  • 常用于 可选类型,引用对象销毁后会自动设为 nil
swift
class Teacher {
  var student: Student?
  deinit { print("Teacher deinit") }
}

class Student {
  weak var teacher: Teacher? // 🔑 解决循环引用
  deinit { print("Student deinit") }
}

4.2 无主引用(unowned)

  • unowned 修饰,不会增加计数。
  • 不会自动置 nil,适合生命周期一致的对象。
swift
class CreditCard {
  unowned let customer: Customer // 永远存在
  init(customer: Customer) { self.customer = customer }
  deinit { print("Card deinit") }
}

class Customer {
  var card: CreditCard?
  deinit { print("Customer deinit") }
}

var c: Customer? = Customer()
c?.card = CreditCard(customer: c!)
c = nil // 两个对象都释放

5. 闭包捕获列表

闭包也可能导致循环引用,需要用 [weak self][unowned self]

swift
class ViewController {
  var name = "VC"
  var callback: (() -> Void)?

  func setup() {
      callback = { [weak self] in
          print(self?.name ?? "nil")
      }
  }

  deinit { print("VC deinit") }
}

总结

  • Swift 使用 ARC 自动管理内存。
  • 循环引用是主要问题,需要 weakunowned 解决。
  • 闭包中捕获 self 时,注意使用捕获列表。

本站总访问