Swift中的ARC(Automatic Reference Counting,自动引用计数)是一种内存管理机制,用于跟踪和管理应用程序中的对象引用计数,确保内存中的对象只在需要的时候存在,当对象的引用计数为0时就会被系统析构掉。
1. 使用弱引用
在以下示例中,类A持有一个强引用类B,类B持有一个弱引用类A。这可以防止循环引用,因为类B不能保持类A的引用计数。当类A释放时,类B的弱引用将自动设置为nil。若没有weak,objA对象的b变量指向objB对象,objB对象的a变量指向objA对象,且都是强引用,这时便造成了循环引用,内存泄漏。
class A {
var b: B?
}
class B {
weak var a: A?
}
var objA: A? = A()
var objB: B? = B()
objA?.b = objB
objB?.a = objA
objA = nil
objB = nil
2. 使用无主引用
在以下示例中,类A持有一个强引用类B,类B持有一个无主引用类A。这可以防止循环引用,因为类B不能保持类A的引用计数。当类A释放时,类B的无主引用将继续指向已释放的对象,这可能会导致运行时错误。因此,需要确保类B在访问类A时检查其无主引用是否为nil。unowned的用法和weak类似,区别在于无主引用是对非可选型变量,而弱引用是对可选型变量。
class A {
var b: B?
}
class B {
unowned var a: A
init(a: A) {
self.a = a
}
}
var objA: A? = A()
var objB: B? = B(a: objA!)
objA?.b = objB
objB = nil
objA = nil
1. 闭包捕获self
在闭包中捕获self可能会导致循环引用。当闭包中捕获self时,它会持有对self的强引用,这可能会导致循环引用。
解决办法是使用weak或unowned来定义捕获的引用。如果闭包可能在self释放之后被调用,应该使用unowned,否则应该使用weak。
class MyClass {
var closure: (() -> Void)?
func someMethod() {
closure = { [weak self] in
self?.someOtherMethod()
}
}
func someOtherMethod() {
// ...
}
}
2. 委托和代理
委托和代理模式可能会导致循环引用。在这个例子中,我们定义了一个协议MyDelegate,MyClass是遵循这个协议的类。同时,我们定义了一个UIViewController的子类MyViewController,它是MyClass的代理对象。在MyViewController中,我们将myClass的代理设置为self,并实现了MyDelegate协议中的方法didSomething()。在MyViewController中,当代理方法被调用时,我们调用了myClass的doSomething()方法。
这个例子中的循环引用问题是,MyViewController持有对myClass的强引用,而myClass持有对MyViewController代理对象的强引用。这意味着,当MyViewController被销毁时,它并不能被释放,因为MyClass仍然持有对它的强引用。而当MyClass被销毁时,它也不能被释放,因为MyViewController仍然持有对它的强引用。这样就形成了循环引用的问题。
为了解决这个问题,我们需要使用weak来声明对代理对象的引用。
protocol MyDelegate: class {
func didSomething()
}
class MyClass {
weak var delegate: MyDelegate?
func doSomething() {
// ...
delegate?.didSomething()
// ...
}
}
class MyViewController: UIViewController, MyDelegate {
let myClass = MyClass()
override func viewDidLoad() {
super.viewDidLoad()
myClass.delegate = self
}
deinit {
print("MyViewController deinit")
}
func didSomething() {
// ...
myClass.doSomething()
// ...
}
}
3. 对象间相互引用
如果两个对象相互持有对方的强引用,那么就会发生循环引用。
解决办法是将其中一个引用定义为弱引用或无主引用。如果两个对象的生命周期相同,则应该使用弱引用,否则应该使用无主引用。
class MyClass {
var otherObject: OtherClass?
// ...
}
class OtherClass {
weak var myObject: MyClass?
// ...
}