📅  最后修改于: 2023-12-03 15:35:13.039000             🧑  作者: Mango
在Swift中,反初始化(deinitialization)是一个可选的方法,可以在对象被释放之前执行清理任务。在这篇文章中,我们将深入探讨Swift中的反初始化。
反初始化是类中的一个方法,以deinit
关键字开头。这个方法没有参数,也没有返回类型。下面是反初始化的基本语法:
deinit {
// 执行清理任务
}
在使用类的时候,当对象被释放时会自动调用该对象的反初始化方法。下面是一个简单的例子:
class MyClass {
deinit {
print("MyClass is being deinitialized")
}
}
var object: MyClass? = MyClass()
object = nil // MyClass is being deinitialized
在这个例子中,我们创建了一个MyClass
类并将其实例保存在一个可选的变量中。当我们将该变量设置为nil
时,MyClass
类的对象被释放,并执行了其反初始化方法。
在了解Swift中反初始化的更多知识之前,我们需要先了解对象的生命周期。一个对象在Swift中的生命周期可以分为以下四个阶段:
当我们使用var
或let
关键字创建一个变量或常量时,Swift会在内存中为该变量或常量分配一段空间,以存储该变量或常量的值。当我们使用这个变量或常量时,我们称这个变量或常量处于“对象使用”阶段。当这个变量或常量不再被使用时,Swift会释放这个变量或常量所占用的内存空间,“对象释放”阶段到来。
当Swift将对象释放时,会自动调用该对象的反初始化方法。反初始化方法是对象生命周期的最后一个阶段,可以执行清理任务,例如释放对象所持有的资源等。
在Swift中,当一个对象的所有强引用计数(strong reference)被释放时,该对象才会被释放。换句话说,只有当该对象不再被任何一个变量持有(strong reference)时,该对象才会被释放。下面是一个例子:
class MyClass {
var property: Int
init() {
property = 0
}
deinit {
print("MyClass is being deinitialized")
}
}
var object1: MyClass? = MyClass()
var object2: MyClass? = object1
object1 = nil // MyClass is not being deinitialized
object2 = nil // MyClass is being deinitialized
在这个例子中,我们创建了一个MyClass
类的对象,并将其赋值给object1
和object2
两个变量。这意味着我们创建了两个指向同一个对象的强引用。因此,即使我们将object1
设置为nil
,对象也不会被释放,因为object2
仍然持有对该对象的强引用。只有当object2
也被设置为nil
时,该对象才会被释放,并执行反初始化方法。
Swift中有两种类型的引用可以在某种程度上解决循环引用(circular reference)的问题:弱引用(weak reference)和无主引用(unowned reference)。这两种引用可以让我们在对象之间建立非强引用关系,以避免循环引用。下面我们将逐个介绍它们。
弱引用是一种非强引用,它可以让一部分对象之间建立非强引用关系。弱引用不会保留引用对象的强引用计数,这意味着当对象的所有强引用计数为0时,该对象可以被Swift自动释放。弱引用通常用于创建一个指向可能不存在的对象的引用,例如在创建对象树时。
在Swift中,我们可以使用weak
关键字创建一个弱引用。下面是一个例子:
class ParentClass {
var child: ChildClass?
deinit {
print("ParentClass is being deinitialized")
}
}
class ChildClass {
weak var parent: ParentClass?
deinit {
print("ChildClass is being deinitialized")
}
}
var parentObject: ParentClass? = ParentClass()
var childObject: ChildClass? = ChildClass()
parentObject?.child = childObject
childObject?.parent = parentObject
parentObject = nil // ParentClass is being deinitialized
childObject = nil // ChildClass is being deinitialized
在这个例子中,我们创建了一个ParentClass
类和一个ChildClass
类。我们在ParentClass
中创建了一个可选的ChildClass
类型的变量,以及在ChildClass
中创建了一个弱引用类型的可选ParentClass
变量。我们将childObject
赋值给parentObject?.child
,同时将parentObject
赋值给childObject?.parent
。这意味着我们创建了两个对象之间的互相指向引用。然后,我们将parentObject
和childObject
设置为nil
,并通过打印语句验证对象正确释放,并执行反初始化方法。
无主引用是另一种非强引用,与弱引用类似,也可以让我们在对象之间建立非强引用关系。无主引用不会保留引用对象的强引用计数,但它也会假定该引用对象将一直存在,因此它永远不会是可选类型。
在Swift中,我们可以使用unowned
关键字创建一个无主引用。下面是一个例子:
class MyClass {
unowned let parent: ParentClass
init(parent: ParentClass) {
self.parent = parent
}
deinit {
print("MyClass is being deinitialized")
}
}
class ParentClass {
var child: MyClass?
deinit {
print("ParentClass is being deinitialized")
}
}
var parentObject: ParentClass? = ParentClass()
var childObject: MyClass? = MyClass(parent: parentObject!)
parentObject?.child = childObject
childObject = nil // MyClass is being deinitialized
parentObject = nil // ParentClass is being deinitialized
在这个例子中,我们创建了一个ParentClass
类和一个MyClass
类。我们在MyClass
中创建了一个无主引用类型的let
型属性parent
,并在MyClass
的初始化方法中初始化它。我们在ParentClass
中创建了一个可选的MyClass
类型的变量child
,并将其赋值给parentObject?.child
。这意味着我们创建了两个对象之间的互相指向引用。然后,我们将childObject
设置为nil
,并通过打印语句验证对象正确释放,并执行反初始化方法。最后,我们将parentObject
设置为nil
,这将释放ParentClass
和MyClass
对象,并执行它们的反初始化方法。
Swift中的延迟存储属性(lazy stored property)是另一种场景,其中反初始化方法也很有用。延迟存储属性是指在第一次被访问时才进行初始化的属性。当一个类的延迟存储属性依赖于其他对象时,我们可能需要在该类的反初始化方法中进行一些清理:释放资源、撤销订阅等。
我们可以将延迟存储属性存储在一个闭包中,并在闭包中执行初始化操作。这个闭包只会在该属性第一次被访问时执行。下面是一个例子:
class MyClass {
var property: Int
lazy var lazyProperty: String = {
print("lazyProperty is being initialized")
return "Hello, world!"
}()
init() {
property = 0
}
deinit {
print("MyClass is being deinitialized")
}
}
var object: MyClass? = MyClass()
print("Before accessing lazyProperty")
print(object?.lazyProperty ?? "")
print("After accessing lazyProperty")
object = nil // MyClass is being deinitialized
在这个例子中,我们创建了一个MyClass
类,并添加了一个延迟存储属性lazyProperty
。在这个属性的定义中,我们将属性存储在一个闭包中,并在闭包中执行了初始化操作。我们创建了一个MyClass
对象,并在对象创建之后,尝试访问lazyProperty
。由于这是第一次访问lazyProperty
,因此闭包会被执行,并返回Hello, world!
。然后我们将object
设置为nil
,这将释放对象并执行其反初始化方法。
反初始化是Swift中一个可选的方法,可以在对象被释放之前执行清理任务。在Swift中,当一个对象的所有强引用计数被释放时,该对象才会被释放。使用弱引用或无主引用可以帮助我们在两个对象之间建立非强引用关系,以避免循环引用。延迟存储属性也可以用于在第一次访问时执行初始化操作,并在类的反初始化方法中进行清理。