初始化
類,結(jié)構(gòu)和枚舉當(dāng) Swift 聲明后準(zhǔn)備初始化類實例。初始值被初始化為存儲屬性,并且新的實例的值也被進一步進行初始化。創(chuàng)建初始化函數(shù)的關(guān)鍵字是通過 init() 方法。Swift 初始化不同于 Objective-C,它不返回任何值。其作用是檢查新創(chuàng)建的實例的其處理前初始化。Swift 還提供了“反初始化”過程中執(zhí)行的內(nèi)存管理操作當(dāng)實例被釋放。
對于存儲的屬性初始化器的作用
存儲的屬性處理實例之前初始化類和結(jié)構(gòu)的實例。 存儲屬性使用初始分配和初始化值,從而消除了需要調(diào)用屬性觀察者。 初始化用于存儲屬性:
創(chuàng)建初始值
要在屬性定義中指定默認屬性值
為特定的數(shù)據(jù)類型,初始化實例 init()方法被使用,init()函數(shù)沒有傳遞參數(shù)。
語法
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
area of rectangle is 72.0
這里結(jié)構(gòu) 'rectangle' 使用成員長寬高為 “double” 的數(shù)據(jù)類型進行初始化。init()方法被用于為新創(chuàng)建的成員的長度和初始化double 類型的數(shù)值。 計算長方形的面積,并通過調(diào)用矩形函數(shù)返回。
通過默認設(shè)置屬性值
Swift 語言提供 init()函數(shù)來初始化存儲的屬性值。此外,用戶必須規(guī)定默認在聲明類或結(jié)構(gòu)的成員初始化屬性值。當(dāng)屬性的值在整個程序中時一樣時,我們可以在聲明部分單獨聲明它,而不是在 init()中初始化。默認情況下,用戶設(shè)置屬性值時能夠繼承被定義為類或結(jié)構(gòu)。
struct rectangle {
var length = 6
var breadth = 12
}
var area = rectangle()
println("area of rectangle is /(area.length*area.breadth)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
area of rectangle is 72.0
在這里,代替聲明長和寬在 init()中,在聲明本身時就初始化值了。
參數(shù)初始化
在 Swfit 語言用戶提供以初始化參數(shù)初始化,使用定義作為 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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
area is: 72.0area is: 432.0
局部及外部參數(shù)
初始化參數(shù)具有類似于的函數(shù)和方法參數(shù)局部和全局參數(shù)名稱。局部參數(shù)聲明用于初始化體,外部參數(shù)聲明訪問用于調(diào)用初始化。Swift 函數(shù)初始化和方法不同,它們不識別哪些初始化用于該函數(shù)調(diào)用。
為了克服這個問題,Swift 引入了一個自動外部名稱為 init()的每個參數(shù)。 這種自動外部名稱是等同的每一個初始化參數(shù)局部名字之前寫入。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Days of a Week is: 1Days of a Week is: 2Days of a Week is: 3Days of a Week is: 4Days of a Week is: 4Days of a Week is: 4
不帶外部名稱參數(shù)
當(dāng)外部名稱不需要一個初始化下劃線“_”,這是用來覆蓋默認行為。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
area is: 180.0area is: 370.0area is: 110.0
可選屬性類型
當(dāng)一些實例存儲的屬性不返回任何值該屬性使用 “optional” 類型,表示“沒有值”則返回特定類型的聲明。當(dāng)存儲的屬性被聲明為“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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
area is: Optional(180.0)area is: Optional(370.0)area is: Optional(110.0)
默認初始化器
默認初始化提供給基類或結(jié)構(gòu)的所有聲明屬性的新實例默認值。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
result is: nilresult is: 98result is: true
上述程序中定義了類的名字為 “defaultexample'。三個成員函數(shù)默認初始化為“studname?”存儲值為 'nil' , “stmark”為98和“pass”的布爾值 “true”。 同樣,在類中的成員的值可以處理的類成員類型前初始化為默認值。
按成員初始化器結(jié)構(gòu)類型
當(dāng)不提供由用戶自定義的初始化,在Swift 結(jié)構(gòu)類型將自動接收“成員逐一初始化”。它的主要功能是初始化新的結(jié)構(gòu)實例逐一初始化的默認成員,然后在新的實例屬性逐一通過名字傳遞給成員初始化。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Area of rectangle is: 24.0Area of rectangle is: 32.0
結(jié)構(gòu)由默認初始化為“length”為“100.0”和“breadth”為“200.0”,初始化期間為它們的成員函數(shù)。但長度和寬度的變量值在處理過程中覆蓋為24.0和32.0。
初始化委托值類型
初始委托定義調(diào)用其它初始化函數(shù)初始化。它的主要功能是充當(dāng)可重用性,以避免在多個初始化代碼重復(fù)。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
(0.0,0.0) (0.0,0.0)(2.0,2.0) 5.0,5.0)(2.5,2.5) (3.0,3.0)
初始化函數(shù)委派規(guī)則
類繼承和初始化
類類型有兩種初始化函數(shù),以檢查是否定義存儲屬性接收初始值,即指定初始化和方便初始化函數(shù)。
指定初始化和便捷初始化器
程序指定初始化
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
res is: 10res is: 10res 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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
res is: 20res is: 30res is: 50
初始化繼承和重寫
Swift 默認不允許其子類繼承其超類初始化函數(shù)為成員類型。繼承適用于超類初始化只能在一定程度上,這將在自動初始化程序繼承進行討論。
當(dāng)用戶需要具有在超類,子類中定義的初始化器,初始化函數(shù)必須由用戶作為自定義實現(xiàn)來定義。 當(dāng)重寫,必須在子類到超類的使用 “override”關(guān)鍵字來聲明。
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)")
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Rectangle: 4 sidesPentagon: 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)
}
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Planet name is: MercuryNo Planets like that: [No Planets]
Failable初始化器
用戶必須被通知當(dāng)在定義一個類,結(jié)構(gòu)或枚舉值的任何初始化失敗時。變量初始化有時會成為一種失敗,由于:
- 無效的參數(shù)值
- 缺少所需的外部來源
- 有條件阻止初始化成功
若要捕獲拋出的初始化方法例外,swift 處理產(chǎn)生一種靈活初始化稱為“failable 初始化”通知,是留給被忽視在初始化結(jié)構(gòu),類或枚舉成員。關(guān)鍵字捕獲 failable 初始值設(shè)定 “init?”。此外,failable 和 非failable 初始化函數(shù)不能使用相同的參數(shù)類型和名稱來定義。
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")
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Student name is specifiedStudent name is left blank
Failable初始值設(shè)定為枚舉
Swift 語言提供了靈活性,可以使用 Failable 初始化函數(shù)通知用戶,從初始化留下來枚舉成員值。
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")
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
With In Block TwoBlock Does Not Exist
Failable初始化器類
當(dāng)枚舉和結(jié)構(gòu)聲明 failable 初始化提醒的初始化失敗,在實現(xiàn)中的任意情況。然而, failable 初始化在類中提醒后,才存儲屬性設(shè)置初始值。
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)")
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Module is Failable Initializers
覆蓋一個Failable初始化器
這樣初始化用戶也有提供子類覆蓋超類的failable 初始化。超級類 failable 初始化也可以在子類非 failable 初始化覆蓋。
覆蓋一個 failable 超類初始化時,nonfailable 子類初始化子類的初始化器不能委派到超類初始化器。
一個nonfailable初始化不能委托給一個failable初始化。
下面給出的程序描述failable和非failable初始化函數(shù)。
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)
}
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Planet name is: MercuryNo 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")
}
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
Student name is specifiedStudent name is left blank
必需的初始化
聲明并初始化每個子類,“required”關(guān)鍵字的需要在init()函數(shù)之前定義。
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()
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
103010
反初始化
一個類實例需要被解除分配之前,“deinitializer”被調(diào)用來釋放內(nèi)存空間。關(guān)鍵字 “deinit' 被用于釋放由系統(tǒng)資源占用的存儲空間。反初始化僅適用于類類型。
反初始化并釋放內(nèi)存空間
Swift 當(dāng)不再需要它們時自動取消分配實例,以釋放資源。Swift 通過自動引用計數(shù)(ARC)處理實例的內(nèi)存管理,如自動引用計數(shù)描述。通常情況下無需進行手動清理,實例會自動被釋放。但是,當(dāng)正在使用自己的資源,可能需要自己進行一些額外的清理。例如,如果創(chuàng)建一個自定義類來打開一個文件,寫一些數(shù)據(jù),可能需要關(guān)閉該文件在類實例釋放之前。
var counter = 0; // for reference counting
class baseclass {
init() {
counter++;
}
deinit {
counter--;
}
}
var print: baseclass? = baseclass()
println(counter)
print = nil
println(counter)
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
10
當(dāng) print = nil 語句省略計數(shù)器的值保持不變,因為它沒有反初始化。
var counter = 0; // for reference counting
class baseclass {
init() {
counter++;
}
deinit {
counter--;
}
}
var print: baseclass? = baseclass()
println(counter)
println(counter)
當(dāng)我們使用 playground 運行上面的程序,得到以下結(jié)果。
11