Swift - 初始化



初始化器用于创建类、结构体或枚举的实例。它确保在使用实例之前,实例的所有属性都设置为合适的值。如果我们在类、结构体或枚举中没有创建初始化器,那么 Swift 将自动为实例创建初始化器。

它们不返回值;它们的主要目标是确保任何类型的新的实例在第一次使用之前被正确初始化。Swift 还提供了一个反初始化过程,用于在实例被释放后执行内存管理操作。

在 Swift 中定义初始化器

在 Swift 中,初始化器是使用 **init** 关键字创建的。它可以有参数,也可以没有参数。

语法

以下是初始化器的语法:

init() {
   //New Instance initialisation goes here
}

示例

这里,结构体 'rectangle' 初始化了成员 'length' 和 'breadth' 为 'Double' 数据类型。Init() 方法用于初始化新创建的成员 length 和 double 的值。矩形的面积通过调用 rectangle 函数计算并返回。

struct rectangle {
   var length: Double
   var breadth: Double

   // Initializer
   init() {
      length = 6
      breadth = 12
   }
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

输出

它将产生以下输出:

area of rectangle is 72.0

在创建任何特定类型的实例时,始终要记住存储属性必须在实例创建之前进行初始化。它们不能处于不确定的状态。我们可以在实例中初始化存储属性,或者通过在其定义的一部分中分配默认值来初始化它们。

通过默认值设置属性值

我们可以使用 init() 初始化器初始化存储属性,或者用户可以默认在声明类或结构体成员时初始化属性值。当属性在整个程序中始终取相同的值时,我们可以单独在声明部分声明它,而不是在 init() 中初始化它。

示例

struct rectangle {

   // Properties with default value
   var length = 6
   var breadth = 12
}

// Instance of rectangle structure
var area = rectangle()
print("Area of rectangle is \(area.length*area.breadth)")

输出

它将产生以下输出:

Area of rectangle is 72

参数初始化

我们可以通过向初始化器传递参数来初始化实例的属性。它是使用 init() 的初始化器定义的一部分。

示例

// Structure
struct Rectangle {

   // Properties
   var length: Double
   var breadth: Double
   var area: Double
    
   // Initializer with parameters
   init(fromLength length: Double, fromBreadth breadth: Double) {
      self.length = length
      self.breadth = breadth
      area = length * breadth
   }
}

// Instance of structure 
let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("area is: \(ar.area)")

输出

它将产生以下输出:

area is: 72.0

局部参数和外部参数

初始化参数同时具有局部参数名称和全局参数名称,类似于函数和方法参数。局部参数声明用于在初始化主体内部访问,而外部参数声明用于调用初始化器。

Swift 初始化器与函数和方法初始化器的不同之处在于,它们不识别哪个初始化器用于调用哪个函数。

为了克服这一点,Swift 为 init() 中的每个参数引入了自动外部名称。此自动外部名称等效于每个初始化参数之前编写的局部名称。

示例

struct Days {
   // Properties
   let sunday, monday, tuesday: Int
    
   // Initializer with parameter names
   init(sunday: Int, monday: Int, tuesday: Int) {
      self.sunday = sunday
      self.monday = monday
      self.tuesday = tuesday
   }
}

// Instance of structure
let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")

输出

它将产生以下输出:

Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3

没有外部名称的参数

当初始化器不需要外部名称时,使用下划线 '_' 来覆盖默认行为。

示例

struct Rectangle {
   var length: Double
    
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
    
   init(frombre bre: Double) {
      length = bre * 30
   }
    
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

输出

它将产生以下输出:

area is: 180.0
area is: 370.0
area is: 110.0

可选属性类型

当存储属性在某些实例中不返回值时,该属性将声明为“可选”类型,表示对于该特定类型“没有返回值”。在初始化期间,声明为“可选”的属性将自动初始化为 nil 值。

示例

struct Rectangle {

   // Optional property type
   var length: Double?
    
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
    
   init(frombre bre: Double) {
      length = bre * 30
   }
    
   init(_ area: Double) {
      length = area
   }
}

// Instances of structure
let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

输出

它将产生以下输出:

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

在初始化期间赋值常量属性

我们允许在初始化时为常量赋值,并且一旦为常量属性赋值,我们就不能进一步修改该值,如果我们尝试这样做,我们将收到错误。此外,类实例的常量属性可以在初始化期间由引入它的类修改,而不是由子类修改。

示例

class Rectangle {

   // Constant property
   let length: Int  

   var breadth: Int

   // Initializer
   init(breadth: Int) {
      self.breadth = breadth
        
      // Assigning a value to the constant property during initialization
      self.length = 34  
   }
    
   // Method using constant property
   func area() -> Int {
      return length * breadth
   }
}

// Creating an instance 
let obj = Rectangle(breadth: 10)

// Accessing the constant property
print("The value of length is: \(obj.length)")

let ar = obj.area()
print("The area of the Rectangle is: \(ar)")

输出

它将产生以下输出:

The value of length is: 34
The area of the Rectangle is: 340

默认初始化器

默认初始化器是在类或结构体不包含任何自定义初始化器或所有属性都具有默认值时,由 Swift 编译器自动创建的初始化器。它们用于创建类的实例或结构体,其所有属性都设置为其默认值。

示例

class defaultexample {

   // Properties with default value
   var stmark = 98
   var pass = true
}

// Creating an instance with default initializer
var result = defaultexample()

// Accessing properties
print("result is: \(result.stmark)")
print("result is: \(result.pass)")

输出

它将产生以下输出:

result is: 98
result is: true

结构体类型的逐一成员初始化器

在 Swift 中,如果结构体类型没有自定义初始化器,那么它将自动接收“逐一成员初始化器”。如果它们具有不包含默认值的存储属性,它们也会接收“逐一成员初始化器”。新的实例属性按名称传递给逐一成员初始化器。

示例

struct Rectangle {
   var length = 100.0, breadth = 200.0
}

// Instance with memberwise initializers 
let area = Rectangle(length: 24.0, breadth: 32.0)

print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")

输出

它将产生以下输出:

Area of rectangle is: 24.0
Area of rectangle is: 32.0

初始化器委托

初始化器委托定义为从其他初始化器调用初始化器。它的主要功能是作为可重用性,以避免在多个初始化器中重复代码。

初始化器委托规则

以下是一些初始化器委托在处理值类型和类类型时遵循的规则:

对于值类型(结构体和枚举)

  • 值类型不支持继承。因此,值类型的初始化器委托在同一类型中调用另一个初始化器。

  • 它没有任何子类的概念。因此,指定初始化器是完整初始化的主要初始化器。

  • 值类型使用 self.init 来引用同一值类型的其他初始化器。

  • 它们会自动为其属性接收逐一成员初始化器。

对于类类型

  • 支持继承。因此,类必须确保在初始化期间它们继承的所有存储属性都分配了合适的值。

  • 它具有子类的概念。因此,类中的指定初始化器可以使用 super.init 调用其直接超类的指定初始化器。

示例

Swift 程序演示值类型的初始化器委托。

struct Car {

   var price: Int
   var quantity: Int

   // Designated initializer
   init(price: Int, quantity: Int) {
      self.price = price
      self.quantity = quantity
   }

   // Convenience initializer delegating to the designated initializer
   init(monzaCar: Int) {
      self.init(price: monzaCar, quantity: monzaCar)
   }

   // Convenience initializer with default values
   init() {
      self.init(price: 2245622, quantity: 1)
   }
}

// Creating instances
let obj1 = Car(price: 2000000, quantity: 1)
let obj2 = Car(monzaCar: 34)
let obj3 = Car()

print(obj1)        
print(obj2)            
print(obj3)  

输出

它将产生以下输出:

Car(price: 2000000, quantity: 1)
Car(price: 34, quantity: 34)
Car(price: 2245622, quantity: 1)

类继承和初始化

众所周知,类具有存储属性,包括它从超类继承的属性。因此,所有这些属性都必须在初始化时初始化为初始值。因此,为了初始化这些属性,Swift 提供了两种类型的初始化器,它们是:

指定初始化器

它是类的主要初始化器。它初始化类的所有属性,并且还可以通过调用超类初始化器来初始化继承的属性。每个类至少定义一个指定初始化器。

语法

以下是指定初始化器的语法:

init(parameterList)
{
   // Statement
}

示例

Swift 程序演示如何创建指定初始化器。

// Super class 
class mainClass {
   var no1 : Int 
    
   // Designated Initializer
   init(no1 : Int) {
      self.no1 = no1 
   }
}

// Sub class
class subClass : mainClass {
   var no2 : Int 
    
   // Designated Initializer
   init(no1 : Int, no2 : Int) {
      self.no2 = no2 
        
      // Calling designated initializer of super class to initialize no1
      super.init(no1:no1) 
   }
}

// Creating instances
let obj1 = mainClass(no1: 10)
let obj2 = subClass(no1: 10, no2: 20)

print("no1:", obj1.no1)
print("no1:\(obj2.no1) and no2: \(obj2.no2)")
输出

它将产生以下输出:

no1: 10
no1:10 and no2: 20

便利初始化器

它是类的辅助初始化器。它可以实现为在同一类中调用指定初始化器,其中指定初始化器的某些参数分配了默认值。它还可以为特定用例或输入值类型创建实例。类不需要便利初始化器。

语法

以下是便利初始化器的语法:

convenience init(parameterList)
{
   // Statement
}

示例

Swift 程序演示如何创建便利初始化器。

class mainClass {
   var no1 : Int 
    
   // Designated Initializer
   init(no1 : Int) {
      self.no1 = no1 
   }
}

class subClass : mainClass {
   var no2 : Int
    
   // Designated Initializer
   init(no1 : Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
    
   // Requires only one parameter for convenient method
   override convenience init(no1: Int)  {
      self.init(no1:no1, no2:0)
   }
}

// Creating instances
let obj1 = mainClass(no1: 20)
let obj2 = subClass(no1: 30, no2: 50)

print("res is: \(obj1.no1)")
print("res is: \(obj2.no1)")
print("res is: \(obj2.no2)")
输出

它将产生以下输出:

res is: 20
res is: 30
res is: 50

初始化器继承和重写

默认情况下,Swift 不允许其子类继承其超类的初始化器以用于其成员类型。它们可以使用 super.init() 调用其超类的初始化器,以确保所有继承的属性都初始化了一些值。

我们允许使用 override 关键字在子类中重写超类的指定初始化器。重写初始化器必须使用 super.init() 调用其超类中的对应初始化器。

正如我们所知,子类默认情况下不能继承其超类的初始化器。但是,如果超类的初始化器可以满足以下条件,那么它们就可以被其子类自动继承:

  • 如果子类没有任何指定初始化器,那么它将自动继承其基类的指定初始化器。

  • 如果子类提供了其所有基类指定初始化器的实现,那么它将自动继承所有基类的便利初始化器。

示例

Swift 程序演示如何重写初始化器。

// Base class
class Sides {
   var corners = 4
   var description: String {
      return "\(corners) sides"
   }
}

// Instance of sides class
let rectangle = Sides()
print("Rectangle: \(rectangle.description)")

// Subclass
class Pentagon: Sides {

   // Overriding initializer
   override init() {
      super.init()
      corners = 5
   }
}

// Instance of Pentagon class
let bicycle = Pentagon()
print("Pentagon: \(bicycle.description)")

输出

它将产生以下输出:

Rectangle: 4 sides
Pentagon: 5 sides

示例

Swift 程序演示指定和便利初始化器如何运作。

class Planet {
   var name: String
    
   init(name: String) {
      self.name = name
   }
    
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
    
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

输出

它将产生以下输出:

Planet name is: Mercury
No Planets like that: [No Planets]

可失败初始化器

并非所有初始化器都能成功初始化值,它们可能会由于以下原因而失败:无效的参数值、缺少所需的外部源或阻止初始化成功的条件。

为了捕获初始化方法抛出的异常,Swift 提供了一种特殊的初始化器类型,称为“可失败初始化器”。可失败初始化器会通知开发者在初始化结构体、类或枚举成员时,某些内容被忽略了。或者我们可以说,可失败初始化器会创建它初始化的类型的可选值。如果发生错误,则此初始化器将返回 nil。一个类、结构体或枚举可以拥有一个或多个可失败初始化器来捕获错误。

使用init? 关键字,我们可以创建一个可失败初始化器。此外,可失败初始化器和不可失败初始化器不能使用相同的参数类型和名称进行定义。

语法

以下是可失败初始化器的语法:

init?(parameterList)
{
   // Statement
}

示例

Swift 程序演示如何创建可失败初始化器。

struct studrecord {
   let stname: String
    
   // Failable initializer
   init?(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}

let stmark = studrecord(stname: "Swing")
if let name = stmark {
   print("Student name:\(name) is specified.")
}

let blankname = studrecord(stname: "")
if blankname == nil {
   print("\nStudent name is left blank")
}

输出

它将产生以下输出:

Student name:studrecord(stname: "Swing") is specified.

Student name is left blank

枚举的可失败初始化器

在 Swift 中,我们也可以对枚举使用可失败初始化器,以便在枚举成员未初始化值时通知用户。它根据一个或多个参数选择合适的枚举情况,如果给定参数与指定的枚举情况不匹配,则初始化器可能会失败。

示例

Swift 程序演示枚举的可失败初始化器。

// Enumeration
enum functions {
   case a, b, c, d

   // Failable initializer
   init?(funct: String) {
      switch funct {
         case "one":
            self = .a
         case "two":
            self = .b
         case "three":
            self = .c
         case "four":
            self = .d
         default:
            return nil
      }
   }
}

let result = functions(funct: "two")
if result != nil {
   print("With In Block Two")
}
let badresult = functions(funct: "five")
if badresult == nil {
   print("Block Does Not Exist")
}
输出

它将产生以下输出:

With In Block Two
Block Does Not Exist

类的可失败初始化器

当与枚举和结构体一起声明时,可失败初始化器会在其实现中的任何情况下都发出初始化失败的警报。但是,类中的可失败初始化器只有在存储属性被设置为初始值后才会发出失败警报。

示例

Swift 程序演示类的可失败初始化器。

// Class
class studrecord {
   let studname: String!
    
   // Failure Initializer
   init?(studname: String) {
      self.studname = studname
      if studname.isEmpty { return nil }
   }
}
if let stname = studrecord(studname: "Failable Initializers") {
   print("Module is \(stname.studname!)")
}
输出

它将产生以下输出:

Module is Failable Initializers

重写可失败初始化器

就像初始化器一样,我们允许在子类中重写超类的可失败初始化器。超类可失败初始化器也可以在子类的不可失败初始化器中被重写。在用不可失败的子类初始化器重写可失败的超类初始化器时,子类初始化器不能委托给超类初始化器。而不可失败的初始化器永远不能委托给可失败的初始化器。

示例

Swift 程序演示重写可失败初始化器。

class Planet {
   var name: String
    
   init(name: String) {
      self.name = name
   }
   
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
    
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
    
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}
输出

它将产生以下输出:

Planet name is: Mercury
No Planets like that: [No Planets]

init! 可失败初始化器

我们知道,我们可以使用 init? 创建可选的可失败初始化器,如果初始化过程失败,它们将返回 nil,否则,它们将返回指定类型的实例。因此,为了隐式展开可选实例,Swift 提供了一种特殊的初始化器类型,即 init!。当错误条件不应该发生时使用它,如果发生错误,程序将在运行时崩溃。我们可以从 init? 委托到 init!,反之亦然。我们可以用 init! 重写 init?,反之亦然。

示例

Swift 程序演示 init! 可失败初始化器。

struct studrecord {
   let stname: String
    
   // init! initializer
   init!(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")
if let name = stmark {
   print("Student name: \(name) is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
   print("Student name is left blank")
}
输出

它将产生以下输出:

Student name: studrecord(stname: "Swing") is specified
Student name is left blank

必需初始化器

类中的必需初始化器是在声明它的类的所有子类中都必须实现的初始化器。要使用required关键字声明必需初始化器,并且实现必需初始化器的所有子类都必须使用required关键字。如果我们正在重写设计的必需初始化器,那么我们不需要在初始化器之前指定override修饰符。

语法

以下是必需初始化器的语法:

required init(parameterList)
{
   // Statement
}

示例

Swift 程序演示必需初始化器。

// Superclass
class classA {

   // Required initializer
   required init() {
      let a = 10
      print(a)
   }
}

// Subclass
class classB: classA {

   // Required initializer
   required init() {
      let b = 30
      print(b)
   }
}

// Instance of subclass and superclass
let obj1 = classA()
let obj2 = classB()

输出

它将产生以下输出:

10
30
10
广告