在Swift 4中宣告的類,結構體和列舉初始化以準備類的範例。 儲存屬性初始化初始值,對於新範例也初始化值,初始化值以準備初始範例資料。 建立初始化由init()
方法執行。 Swift 4初始化程式與Objective-C的不同之處在於它不返回任何值。 它是在處理之前檢查新建立範例的初始化。 Swift 4還提供了「取消初始化」過程,用於在取消分配範例後執行記憶體管理操作。
儲存屬性必須在處理範例之前初始化其類和結構的範例。 儲存屬性使用初始化程式來分配和初始化值,從而消除了呼叫屬性觀察者的需要。 初始化程式用於儲存屬性。
init()
。 init()
函式內沒有傳遞引數。語法
init() {
//New Instance initialization goes here
}
範例程式碼
struct rectangle {
var length: Double
var breadth: Double
init() {
length = 6
breadth = 12
}
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")
當使用playground 執行上述程式時,得到以下結果 -
area of rectangle is 72.0
這裡結構體rectangle
初始化成員:length
和breadth
為Double
資料型別。 Init()
方法用於初始化新建立的成員:length
和breadth
的double
值。 通過呼叫rectangle
函式計算並返回矩形面積。
Swift 4語言提供Init()
函式來初始化儲存的屬性值。 此外,使用者可以在宣告類或結構成員時預設初始化屬性值。 當屬性在整個程式中單獨使用相同的值時,可以單獨在宣告部分宣告它,而不用在init()
中初始化它。 預設情況下,設定屬性值會在為類或結構定義繼承時啟用。
struct rectangle {
var length = 6
var breadth = 12
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")
當使用playground 執行上述程式時,得到以下結果 -
area of rectangle is 72
這裡不是在init()
中宣告長度和寬度,而是在宣告中初始化值。
在Swift 4語言中,使用者可以使用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)
print("area is: \(ar.area)")
let are = Rectangle(fromLeng: 36, fromBread: 12)
print("area is: \(are.area)")
當使用playground 執行上述程式時,得到以下結果 -
area is: 72.0
area is: 432.0
初始化引數具有與函式和方法引數類似的區域性和全域性引數名稱。 區域性引數宣告用於在初始化體內存取,外部引數宣告用於呼叫初始化器。 Swift 4初始化器與函式和方法初始化器不同,它們不能識別哪個初始化器用於呼叫哪些函式。
要解決這個問題,Swift 4為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)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")
let weekdays = Days(daysofaweek: 4)
print("Days of a Week is: \(weekdays.sunday)")
print("Days of a Week is: \(weekdays.monday)")
print("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)
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)")
當使用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)
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)")
當使用 playground 執行上述程式時,得到以下結果 -
area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)
初始化還允許使用者修改常數屬性的值。 在初始化期間,類屬性允許類範例由超類而不是子類修改。 例如,在前一個程式中考慮length
在主類中宣告為’變數’。 以下程式變數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)
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)")
當使用 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()
print("result is: \(result.studname)")
print("result is: \(result.stmark)")
print("result is: \(result.pass)")
當使用 playground 執行上述程式時,得到以下結果 -
result is: nil
result is: 98
result is: true
上面的程式定義為類名為defaultexample
。 預設情況下,三個成員函式被初始化為studname
儲存nil
值,stmark
為98
,pass
為布林值true
。 同樣,在處理類成員型別之前,可以將類中的成員值初始化為預設值。
當使用者不提供自定義初始化程式時,Swift 4中的結構型別將自動接收「成員初始化程式」。 它的主要功能是使用預設的成員初始化初始化新結構範例,然後將新範例屬性按名稱傳遞給成員初始化。
struct Rectangle {
var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)
print("Area of rectangle is: \(area.length)")
print("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
。 但是在處理變數length
和breadth
期間,覆蓋新值為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()
print("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))
print("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))
print("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 } |
convenience 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)
print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("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)
print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")
當使用 playground 執行上述程式時,得到以下結果 -
res is: 20
res is: 30
res is: 50
預設情況下,Swift 4不允許子類為成員型別繼承超類初始值設定項。 繼承僅在某種程度上適用於超類初始值設定項,這將在自動初始化程式繼承中討論。
當使用者需要在超類中定義初始化器時,具有初始化器的子類必須由使用者定義為自定義實現。 當子類必須重寫超類覆蓋時,必須宣告關鍵字。
class sides {
var corners = 4
var description: String {
return "\(corners) sides"
}
}
let rectangle = sides()
print("Rectangle: \(rectangle.description)")
class pentagon: sides {
override init() {
super.init()
corners = 5
}
}
let bicycle = pentagon()
print("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")
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)
}
}
當使用 playground 執行上述程式時,得到以下結果 -
Planet name is: Mercury
No Planets like that: [No Planets]
在定義類,結構或列舉值時,如果有任何初始化程式失敗,則必須通知使用者。 由於以下情況,變數初始化有時會失敗 -
要捕獲初始化方法丟擲的異常,Swift 4生成一個名為failable initializer
的初始化器,以通知使用者在初始化結構,類或列舉成員時不會注意到某些內容。 捕獲可用初始化程式的關鍵字是init?
。 此外,不能使用相同的引數型別和名稱定義可用和不可用的初始值設定項。
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 {
print("Student name is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("Student name is left blank")
}
當使用 playground 執行上述程式時,得到以下結果 -
Student name is specified
Student name is left blank
Swift 4語言提供了列舉的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 {
print("With In Block Two")
}
let badresult = functions(funct: "five")
if badresult == nil {
print("Block Does Not Exist")
}
當使用 playground 執行上述程式時,得到以下結果 -
With In Block Two
Block Does Not Exist
使用列舉和結構宣告時,可用的初始化程式會在其實現中的任何情況下警告初始化失敗。 但是,類中的可用初始化程式僅在儲存的屬性設定為初始值後才會警告失敗。
class studrecord {
let studname: String!
init?(studname: String) {
self.studname = studname
if studname.isEmpty { return nil }
}
}
if let stname = studrecord(studname: "Failable Initializers") {
print("Module is \(stname.studname)")
}
當使用 playground 執行上述程式時,得到以下結果 -
Module is Optional("Failable Initializers")
與初始化一樣,使用者也可以覆蓋子類中的超類可失敗初始化程式。 超類可失敗的初始化也可以在子類可失敗的初始化器中覆蓋。
當使用可失敗的子類初始化覆蓋可失敗的超類初始化程式時,子類初始化程式無法委託超類初始化程式。可失敗初始化程式永遠不能委託給可失敗初始化程式。
下面給出的程式描述了可失敗和可失敗初始化器。
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)
}
}
當使用 playground 執行上述程式時,得到以下結果 -
Planet name is: Mercury
No Planets like that: [No Planets]
Swift 4提供init?
定義一個可選的範例failable
初始化程式。 定義特定型別init!
的隱式解包的可選範例。
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 {
print("Student name is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
print("Student name is left blank")
}
當使用 playground 執行上述程式時,得到以下結果 -
Student name is specified
Student name is left blank
要宣告初始化每個子類需要在init()
函式之前使用required
關鍵字定義。
class classA {
required init() {
var a = 10
print(a)
}
}
class classB: classA {
required init() {
var b = 30
print(b)
}
}
let res = classA()
let print = classB()
當使用 playground 執行上述程式時,得到以下結果 -
10
30
10