实用百科通
霓虹主题四 · 更硬核的阅读氛围

Swift弱引用和强引用:避免循环引用的关键

发布时间:2025-12-15 03:52:13 阅读:271 次

Swift中的强引用是什么

在Swift中,默认的引用关系都是强引用。只要有一个强引用指向某个对象,这个对象就不会被销毁。比如你定义一个类实例,并用一个变量去持有它,这个变量就是强引用。

举个生活里的例子:就像两个人互相拽着对方的手,谁都不松开,那就永远分不开。在代码里,这种“不放手”会导致内存无法释放。

class Person {
let name: String
init(name: String) {
self.name = name
}
deinit {
print("\(name) 被释放了")
}
}

var person: Person? = Person(name: "小明")
person = nil // 此时才会触发 deinit

只有当所有强引用都断开,比如把 person 设为 nil,对象才会被释放。

什么时候需要弱引用

当两个对象相互持有对方时,就容易出现循环引用。比如,父亲有孩子,孩子也记录自己的父亲。如果都用强引用,那谁都不会被释放。

这时候就需要有人“放手”。弱引用(weak)就是用来解决这个问题的。它不会增加引用计数,也不会阻止对象被销毁。

注意:弱引用必须是可选类型,并且要用 weak 关键字声明。

class Father {
let name: String
var child: Child?
init(name: String) {
self.name = name
}
deinit {
print("Father \(name) 被释放了")
}
}

class Child {
let name: String
weak var father: Father?
init(name: String, father: Father?) {
self.name = name
self.father = father
}
deinit {
print("Child \(name) 被释放了")
}
}

这里 Child 对 Father 的引用是 weak,所以即使 Father 持有 Child,Child 也不会“拖住”Father 不让其释放。

弱引用的实际效果

运行下面这段代码:

var dad: Father? = Father(name: "老王")
var kid: Child? = Child(name: "小王", father: dad)
dad?.child = kid

dad = nil // 输出:Father 老王 被释放了
kid = nil // 输出:Child 小王 被释放了

可以看到,dad 被设为 nil 后,Father 实例立即被释放,哪怕 Child 还持有它——因为是弱引用,不影响释放。

除了weak,还有unowned

Swift还提供 unowned 引用,它也不增加引用计数,但和 weak 不同的是,unowned 假定对象一直存在,不会变成 nil。如果对象已经被释放你还访问 unowned 引用,程序会崩溃。

适用于你知道引用对象生命周期更长的情况,比如闭包里捕获 self,但要非常小心。

class NetworkManager {
var completionHandler: (() -> Void)?

func fetchData() {
URLSession.shared.dataTask(with: URL(string: "https://example.com")!) { [unowned self] _, _, _ in
self.handleData()
}.resume()
}

func handleData() { }
deinit {
print("NetworkManager 释放")
}
}

这里用 unowned 是因为网络请求完成前,NetworkManager 通常不会被释放。但如果提前释放了,就会 crash。所以大多数情况下,weak 更安全。