Swift初始化
類,結構和枚舉當 Swift 聲明後準備初始化類實例。初始值被初始化為存儲屬性,並且新的實例的值也被進一步進行初始化。創建初始化函數的關鍵字是通過 init() 方法。Swift 初始化不同於 Objective-C,它不返回任何值。其作用是檢查新創建的實例的其處理前初始化。Swift 還提供了“反初始化”過程中執行的內存管理操作當實例被釋放。
對於存儲的屬性初始化器的作用
存儲的屬性處理實例之前初始化類和結構的實例。 存儲屬性使用初始分配和初始化值,從而消除了需要調用屬性觀察者。 初始化用於存儲屬性:
-
創建初始值
-
要在屬性定義中指定默認屬性值
-
為特定的數據類型,初始化實例 init()方法被使用,init()函數冇有傳遞參數。
語法
init() { //New Instance initialization goes here }
示例
struct rectangle { var length: Double var breadth: Double init() { length = 6 breadth = 12 } } var area = rectangle() println("area of rectangle is \(area.length*area.breadth)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area of rectangle is 72.0
這裡結構 'rectangle' 使用成員長寬高為 “double” 的數據類型進行初始化。init()方法被用於為新創建的成員的長度和初始化double 類型的數值。 計算長方形的麵積,並通過調用矩形函數返回。
通過默認設置屬性值
Swift 語言提供 init()函數來初始化存儲的屬性值。此外,用戶必須規定默認在聲明類或結構的成員初始化屬性值。當屬性的值在整個程序中時一樣時,我們可以在聲明部分單獨聲明它,而不是在 init()中初始化。默認情況下,用戶設置屬性值時能夠繼承被定義為類或結構。
struct rectangle { var length = 6 var breadth = 12 } var area = rectangle() println("area of rectangle is \(area.length*area.breadth)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area of rectangle is 72.0
在這裡,代替聲明長和寬在 init()中,在聲明本身時就初始化值了。
參數初始化
在 Swfit 語言用戶提供以初始化參數初始化,使用定義作為 init()的一部分。
struct Rectangle { var length: Double var breadth: Double var area: Double init(fromLength length: Double, fromBreadth breadth: Double) { self.length = length self.breadth = breadth area = length * breadth } init(fromLeng leng: Double, fromBread bread: Double) { self.length = leng self.breadth = bread area = leng * bread } } let ar = Rectangle(fromLength: 6, fromBreadth: 12) println("area is: \(ar.area)") let are = Rectangle(fromLeng: 36, fromBread: 12) println("area is: \(are.area)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area is: 72.0 area is: 432.0
局部及外部參數
初始化參數具有類似於的函數和方法參數局部和全局參數名稱。局部參數聲明用於初始化體,外部參數聲明訪問用於調用初始化。Swift 函數初始化和方法不同,它們不識彆哪些初始化用於該函數調用。
為了克服這個問題,Swift 引入了一個自動外部名稱為 init()的每個參數。 這種自動外部名稱是等同的每一個初始化參數局部名字之前寫入。
struct Days { let sunday, monday, tuesday: Int init(sunday: Int, monday: Int, tuesday: Int) { self.sunday = sunday self.monday = monday self.tuesday = tuesday } init(daysofaweek: Int) { sunday = daysofaweek monday = daysofaweek tuesday = daysofaweek } } let week = Days(sunday: 1, monday: 2, tuesday: 3) println("Days of a Week is: \(week.sunday)") println("Days of a Week is: \(week.monday)") println("Days of a Week is: \(week.tuesday)") let weekdays = Days(daysofaweek: 4) println("Days of a Week is: \(weekdays.sunday)") println("Days of a Week is: \(weekdays.monday)") println("Days of a Week is: \(weekdays.tuesday)")
當我們使用 playground 運行上麵的程序,得到以下結果。
Days of a Week is: 1 Days of a Week is: 2 Days of a Week is: 3 Days of a Week is: 4 Days of a Week is: 4 Days of a Week is: 4
不帶外部名稱參數
當外部名稱不需要一個初始化下劃線“_”,這是用來覆蓋默認行為。
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) println("area is: \(rectarea.length)") let rearea = Rectangle(370.0) println("area is: \(rearea.length)") let recarea = Rectangle(110.0) println("area is: \(recarea.length)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area is: 180.0 area is: 370.0 area is: 110.0
可選屬性類型
當一些實例存儲的屬性不返回任何值該屬性使用 “optional” 類型,表示“冇有值”則返回特定類型的聲明。當存儲的屬性被聲明為“optional”,它會自動初始化值是'nil' 在其初始化過程中。
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) println("area is: \(rectarea.length)") let rearea = Rectangle(370.0) println("area is: \(rearea.length)") let recarea = Rectangle(110.0) println("area is: \(recarea.length)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area is: Optional(180.0) area is: Optional(370.0) area is: Optional(110.0)
修改常量屬性在初始化時
初始化還允許用戶修改的常量屬性的值。在初始化期間,類屬性允許它的類的實例被超類修改,而不是由子類進行修改。考慮在之前的程序“長度”的例子,被聲明為主類 “變量”。下麵的程序變量 'length' 修改為'常量'變量。
struct Rectangle { let 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) println("area is: \(rectarea.length)") let rearea = Rectangle(370.0) println("area is: \(rearea.length)") let recarea = Rectangle(110.0) println("area is: \(recarea.length)")
當我們使用 playground 運行上麵的程序,得到以下結果。
area is: Optional(180.0) area is: Optional(370.0) area is: Optional(110.0)
默認初始化器
默認初始化提供給基類或結構的所有聲明屬性的新實例默認值。
class defaultexample { var studname: String? var stmark = 98 var pass = true } var result = defaultexample() println("result is: \(result.studname)") println("result is: \(result.stmark)") println("result is: \(result.pass)")
當我們使用 playground 運行上麵的程序,得到以下結果。
result is: nil result is: 98 result is: true
上述程序中定義了類的名字為 “defaultexample'。三個成員函數默認初始化為“studname?”存儲值為 'nil' , “stmark”為98和“pass”的布爾值 “true”。 同樣,在類中的成員的值可以處理的類成員類型前初始化為默認值。
按成員初始化器結構類型
當不提供由用戶自定義的初始化,在Swift 結構類型將自動接收“成員逐一初始化”。它的主要功能是初始化新的結構實例逐一初始化的默認成員,然後在新的實例屬性逐一通過名字傳遞給成員初始化。
struct Rectangle { var length = 100.0, breadth = 200.0 } let area = Rectangle(length: 24.0, breadth: 32.0) println("Area of rectangle is: \(area.length)") println("Area of rectangle is: \(area.breadth)")
當我們使用 playground 運行上麵的程序,得到以下結果。
Area of rectangle is: 24.0 Area of rectangle is: 32.0
結構由默認初始化為“length”為“100.0”和“breadth”為“200.0”,初始化期間為它們的成員函數。但長度和寬度的變量值在處理過程中覆蓋為24.0和32.0。
初始化委托值類型
初始委托定義調用其它初始化函數初始化。它的主要功能是充當可重用性,以避免在多個初始化代碼重複。
struct Stmark { var mark1 = 0.0, mark2 = 0.0 } struct stdb { var m1 = 0.0, m2 = 0.0 } struct block { var average = stdb() var result = Stmark() init() {} init(average: stdb, result: Stmark) { self.average = average self.result = result } init(avg: stdb, result: Stmark) { let tot = avg.m1 - (result.mark1 / 2) let tot1 = avg.m2 - (result.mark2 / 2) self.init(average: stdb(m1: tot, m2: tot1), result: result) } } let set1 = block() println("student result is: \(set1.average.m1, set1.average.m2) \(set1.result.mark1, set1.result.mark2)") let set2 = block(average: stdb(m1: 2.0, m2: 2.0), result: Stmark(mark1: 5.0, mark2: 5.0)) println("student result is: \(set2.average.m1, set2.average.m2) \(set2.result.mark1, set2.result.mark2)") let set3 = block(avg: stdb(m1: 4.0, m2: 4.0), result: Stmark(mark1: 3.0, mark2: 3.0)) println("student result is: \(set3.average.m1, set3.average.m2) \(set3.result.mark1, set3.result.mark2)")
當我們使用 playground 運行上麵的程序,得到以下結果。
(0.0,0.0) (0.0,0.0) (2.0,2.0) 5.0,5.0) (2.5,2.5) (3.0,3.0)
初始化函數委派規則
值類型 | 類類型 |
不支持像結構和枚舉值類型繼承。參照其他初始化函數通過 self.init 完成 | 支持繼承。檢查所有存儲的屬性值初始化 |
類繼承和初始化
類類型有兩種初始化函數,以檢查是否定義存儲屬性接收初始值,即指定初始化和方便初始化函數。
指定初始化和便捷初始化器
指定的初始化 | 便捷初始化器 |
作為一個類主要的初始化 | 作為支持一個類初始化 |
所有的類屬性初始化和適當的超類的初始化被要求進一步初始化 | 指定的初始化程序被調用,便捷初始化創建類的實例為特定用例或輸入值類型 |
每個類至少有一個指定初始化定義 | 非必須在便捷初始化函數強製規定在類不需要初始化函數。 |
Init(parameters) { statements } | 便捷 init(parameters) { statements } |
程序指定初始化
class mainClass { var no1 : Int // local storage init(no1 : Int) { self.no1 = no1 // initialization } } class subClass : mainClass { var no2 : Int // new subclass storage init(no1 : Int, no2 : Int) { self.no2 = no2 // initialization super.init(no1:no1) // redirect to superclass } } let res = mainClass(no1: 10) let print = subClass(no1: 10, no2: 20) println("res is: \(res.no1)") println("res is: \(print.no1)") println("res is: \(print.no2)")
當我們使用 playground 運行上麵的程序,得到以下結果。
res is: 10 res is: 10 res is: 20
程序便捷的初始化
class mainClass { var no1 : Int // local storage init(no1 : Int) { self.no1 = no1 // initialization } } class subClass : mainClass { var no2 : Int 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) } } let res = mainClass(no1: 20) let print = subClass(no1: 30, no2: 50) println("res is: \(res.no1)") println("res is: \(print.no1)") println("res is: \(print.no2)")
當我們使用 playground 運行上麵的程序,得到以下結果。
res is: 20 res is: 30 res is: 50
初始化繼承和重寫
Swift 默認不允許其子類繼承其超類初始化函數為成員類型。繼承適用於超類初始化隻能在一定程度上,這將在自動初始化程序繼承進行討論。
當用戶需要具有在超類,子類中定義的初始化器,初始化函數必須由用戶作為自定義實現來定義。 當重寫,必須在子類到超類的使用 “override”關鍵字來聲明。
class sides { var corners = 4 var description: String { return "\(corners) sides" } } let rectangle = sides() println("Rectangle: \(rectangle.description)") class pentagon: sides { override init() { super.init() corners = 5 } } let bicycle = pentagon() println("Pentagon: \(bicycle.description)")
當我們使用 playground 運行上麵的程序,得到以下結果。
Rectangle: 4 sides Pentagon: 5 sides
指定和便捷初始化在動作中
class Planet { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[No Planets]") } } let plName = Planet(name: "Mercury") println("Planet name is: \(plName.name)") let noplName = Planet() println("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) } }
當我們使用 playground 運行上麵的程序,得到以下結果。
Planet name is: Mercury No Planets like that: [No Planets]
Failable初始化器
用戶必須被通知當在定義一個類,結構或枚舉值的任何初始化失敗時。變量初始化有時會成為一種失敗,由於:
-
無效的參數值
-
缺少所需的外部來源
-
有條件阻止初始化成功
若要捕獲拋出的初始化方法例外,swift 處理產生一種靈活初始化稱為“failable 初始化”通知,是留給被忽視在初始化結構,類或枚舉成員。關鍵字捕獲 failable 初始值設定 “init?”。此外,failable 和 非failable 初始化函數不能使用相同的參數類型和名稱來定義。
struct studrecord { let stname: String init?(stname: String) { if stname.isEmpty {return nil } self.stname = stname } } let stmark = studrecord(stname: "Swing") if let name = stmark { println("Student name is specified") } let blankname = studrecord(stname: "") if blankname == nil { println("Student name is left blank") }
當我們使用 playground 運行上麵的程序,得到以下結果。
Student name is specified Student name is left blank
Failable初始值設定為枚舉
Swift 語言提供了靈活性,可以使用 Failable 初始化函數通知用戶,從初始化留下來枚舉成員值。
enum functions { case a, b, c, d 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 { println("With In Block Two") } let badresult = functions(funct: "five") if badresult == nil { println("Block Does Not Exist") }
當我們使用 playground 運行上麵的程序,得到以下結果。
With In Block Two Block Does Not Exist
Failable初始化器類
當枚舉和結構聲明 failable 初始化提醒的初始化失敗,在實現中的任意情況。然而, failable 初始化在類中提醒後,才存儲屬性設置初始值。
class studrecord { let studname: String! init?(studname: String) { self.studname = studname if studname.isEmpty { return nil } } } if let stname = studrecord(studname: "Failable Initializers") { println("Module is \(stname.studname)") }
當我們使用 playground 運行上麵的程序,得到以下結果。
Module is Failable Initializers
覆蓋一個Failable初始化器
這樣初始化用戶也有提供子類覆蓋超類的failable 初始化。超級類 failable 初始化也可以在子類非 failable 初始化覆蓋。
覆蓋一個 failable 超類初始化時,nonfailable 子類初始化子類的初始化器不能委派到超類初始化器。
一個nonfailable初始化不能委托給一個failable初始化。
下麵給出的程序描述failable和非failable初始化函數。
class Planet { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "[No Planets]") } } let plName = Planet(name: "Mercury") println("Planet name is: \(plName.name)") let noplName = Planet() println("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) } }
當我們使用 playground 運行上麵的程序,得到以下結果。
Planet name is: Mercury No Planets like that: [No Planets]
init! Failable初始化器
Swift 提供 “init?”定義一個可選實例failable初始化。要定義特定類型的隱式解包可選的 'int! ' 被指定。
struct studrecord { let stname: String init!(stname: String) { if stname.isEmpty {return nil } self.stname = stname } } let stmark = studrecord(stname: "Swing") if let name = stmark { println("Student name is specified") } let blankname = studrecord(stname: "") if blankname == nil { println("Student name is left blank") }
當我們使用 playground 運行上麵的程序,得到以下結果。
Student name is specified Student name is left blank
必需的初始化
聲明並初始化每個子類,“required”關鍵字的需要在init()函數之前定義。
class classA { required init() { var a = 10 println(a) } } class classB: classA { required init() { var b = 30 println(b) } } let res = classA() let print = classB()
當我們使用 playground 運行上麵的程序,得到以下結果。
10 30 10