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
廣告