Swift 中的初始化2025年3月17日 | 阅读 10 分钟 在面向对象编程语言中,我们需要实例化类来使用它们的属性和函数。在 Swift 中,初始化可以定义为准备类、结构体和枚举的实例。它允许我们为每个存储的属性设置初始值。我们可以在初始化时放置所需的代码。 我们可以通过定义初始化器来执行初始化,初始化器可以定义为实例化特定类型时调用的特殊方法。在 Swift 中,初始化器不返回值。我们还可以实现反初始化器,用于在实例被释放之前放置任何清理代码。 存储属性的初始值Swift 中的初始化器之所以变得更加重要,是因为我们不能在中间状态拥有存储属性。我们必须在初始化器中将所有存储属性设置为初始值,或者在声明时分配默认值。 初始化器正如我们在本文前面讨论过的,初始化器用于创建特定类型的新实例。初始化器可以使用 init 关键字定义,如下所示。 让我们考虑下面的例子,它定义了一个名为 Employee 的类,该类有一个属性 name 和一个初始化器,用于初始化 name。 我们可以在声明时为类属性提供默认值。在上面的例子中,我们本可以不在写初始化器的情况下,在声明时初始化 name 属性,如下所示。 我们还可以通过在创建对象时提供初始化参数来自定义初始化。初始化参数在功能上与函数和方法参数相似。 让我们考虑下面的例子,它创建了一个 Student 类。一个学生可以有姓名、id 和年龄。我们在创建学生时初始化学生的属性。 输出 "name: John, id: 1, age: 18" 我们可以定义带有参数名的参数,用于初始化器的主体内部。还可以有一个参数标签,在调用初始化器时使用。 在这里,我们必须注意到初始化器不像方法和函数那样有特定的名称;因此,参数名和参数标签在识别正在调用哪个初始化器方面起着重要作用。但是,调用初始化器需要参数标签。 让我们看以下示例。 输出 "URL: , param: [\"name\": \"John\"], method: POST" "URL: https://www.google.com, param: [:], method: GET" 但是,与方法调用一样,Swift 允许我们使用下划线 (_) 来表示我们不想显式提供任何参数标签。让我们考虑使用下划线 (_) 作为参数标签的示例。 可选属性我们的类有可能有一个属性可能有一个值,也可能没有,即我们在初始化时无法设置它的值。在这种情况下,我们需要将这些属性定义为可选的。可选属性默认初始化为 nil。考虑以下示例,其中 department 类可能有关联的员工,也可能没有。这些属性在初始化时被设置为可选。 这将在控制台打印以下输出。 "John" "David" 初始化常量属性常量属性的值一旦初始化就无法更改。但是,我们可以定义一个没有值的常量属性,但我们必须在类中仅通过初始化来为该属性设置值。我们以后无法在应用程序中更改该属性的值。 请看以下示例。 这将在控制台产生以下错误。 error: cannot assign to property: 'name' is a 'let' constant dep.name = "CS" ~~~~^~~~ MyPlaygroundInit.playground:11:5: note: change 'let' to 'var' to make it mutable let name:String ^~~ var 默认初始化我们可以使用 Swift 中的默认初始化器来初始化任何结构和类。默认初始化器用于为其所有属性提供默认值。当类中没有初始化器时,我们可以使用默认初始化器。换句话说,我们可以说默认初始化器以所有属性都设置为其默认值的方式创建新实例。 请看以下示例。 由于 Department 类的所有属性都设置为其默认值,因此它会自动实现一个默认初始化器,该初始化器以其默认值创建 Department 的新实例。在示例中,name 属性默认设置为 nil,因为它是一个可选属性。 结构类型的成员初始化器如果我们观察结构类型,我们会注意到结构类型在没有自定义初始化器的情况下具有成员初始化器。结构类型提供了一个默认初始化器,它不对其属性的默认值进行处理。 考虑以下示例,其中有一个名为 Color 的结构,它有三个成员 Red、Green 和 Blue。我们可以在实例化 Color 结构时提供它们的值。 当结构属性具有默认值时,我们可以在成员初始化器中选择性地为已初始化的值传递值,如下例所示。 在上面的例子中,我们也可以传递红色值来覆盖其默认值。 值类型的初始化委托我们可以从另一个初始化器调用初始化器,以重用它们来初始化值。这个过程称为初始化委托,以避免初始化值的重复代码。 初始化委托对于值类型和实例类型的处理方式不同。值类型不支持继承;因此,值类型的初始化委托过程很简单。在值类型中,初始化器只能委托给它们自己提供的另一个初始化器。 对于值类型,我们可以使用 self.init 来引用同一值类型中的其他初始化器。但是,我们必须注意到 self.init 只能在初始化器本身内部调用。如果为任何值类型定义自定义初始化器,则无法访问该类型的默认初始化器。 让我们考虑以下示例,其中有一个名为 Item 的结构,它引用了两个支持结构 Color 来定义 Item 的颜色和大小。 但是,我们可以通过以下三种方式为 Item 结构定义三个初始化器,即通过使用 Item 属性的默认值,或通过设置特定属性。 第一个 Item 初始化器 init() 类似于结构体的默认初始化器,用于为 Item 属性分配默认值。如果我们使用 init() { } 来为 Item 结构分配默认值,如下所示。 第二个初始化器 init(name:color:size) 类似于结构体在没有自定义初始化器时具有的成员初始化器。 第三个初始化器 init(name:red:size) 比前两个更复杂一些。它接收一个红色值,用于决定其他颜色因子,即绿色和蓝色。一旦我们计算出颜色,就可以从初始化器中调用 init(name:red:size)。 引用类型的初始化我们需要确保类的所有存储属性,包括它继承的属性,都在初始化期间被分配了一个初始值。 为此,Swift 提供了两种类型的初始化器,它们有助于类类型确保所有属性都分配了一个初始值。 类初始化器的类型如下所示。 指定初始化器指定初始化器用作类的主要初始化器。指定初始化器初始化类的所有属性,并调用适当的超类初始化器以继续初始化。指定初始化器被视为初始化过程开始的起点。类通常不具有多个初始化器。但是,每个类必须至少有一个指定初始化器。声明指定初始化器的语法如下。 便捷初始化器便捷初始化器是类的辅助初始化器,作为指定初始化器的支持初始化器。我们可以在类中有一个便捷初始化器,它调用同一个类中的指定初始化器。我们还可以使用便捷初始化器来实例化类,以用于某些特定的用例或输入类型。 但是,如果类不需要便捷初始化器,则不必在其中使用。声明便捷初始化器的语法如下。 类的初始化委托Swift 提供了以下三个简单规则来定义指定初始化器和便捷初始化器之间的关系。
换句话说,我们可以说便捷初始化器总是跨类级别委托,而指定初始化器则向上委托到类级别。 让我们考虑下面的例子,它使用便捷和指定初始化器来初始化类中的存储属性。 在上面的例子中,Person 类有一个指定初始化器和一个便捷初始化器。Person 类可以使用一个名为 name 的特定参数来实例化,如下所示。 在这里,Person 类中的指定初始化器确保所有存储属性都已完全初始化。但是,Person 类还提供了一个便捷初始化器,可以通过不提供 name 来实例化 Person 类。init() 初始化器调用具有默认名称 ("Unnamed") 的指定 init,并为 Person 的 name 赋值。 现在,让我们定义层次结构中的另一个类,即 Employee 类。它在层次结构中添加了两个属性:salary 和 id。它还定义了两个初始化器来初始化存储的属性。 Employee 类有一个指定初始化器,可用于设置新实例的所有属性。在指定初始化器中,salary 和 id 首先被初始化,然后调用超类的指定 init。这称为两阶段初始化,将在本文中讨论。 但是,Employee 类还包含一个便捷初始化器,可以使用 name 来实例化 Employee 类。它为 Employee 的 salary 和 id 提供默认值。使用便捷初始化器创建 Employee 类更方便,因为我们在创建对象时不需要提供 salary 和 Id 的值。 在这里,我们还必须注意到 Employee 类中使用的便捷初始化器接受与 Person 类中的指定初始化器相同的参数名称。这个便捷初始化器覆盖了其超类中的一个指定初始化器。 可以使用以下三种方式实例化 Employee 类。 |
我们请求您订阅我们的新闻通讯以获取最新更新。