本節(jié)知識點(diǎn)
- 構(gòu)造函數(shù)的介紹
- 構(gòu)造函數(shù)的基本使用
- 自定義構(gòu)造函數(shù)
- 屬性與構(gòu)造函數(shù)
1. 構(gòu)造函數(shù)的介紹
- 構(gòu)造函數(shù)類似于OC中的初始化方法:init方法
- 默認(rèn)情況下在創(chuàng)建一個類時,必然會調(diào)用一個構(gòu)造函數(shù)
- 即便是沒有編寫任何構(gòu)造函數(shù)拆挥,編譯器也會提供一個默認(rèn)的構(gòu)造函數(shù)胶征。
- 如果是繼承自NSObject,可以對父類的構(gòu)造函數(shù)進(jìn)行重寫, 必須在構(gòu)造方法前添加
override
關(guān)鍵字
- 如果基類是自己本身, 則沒有父類, 即不需要在前面添加
override
關(guān)鍵字
init(參數(shù)列表){ 初始化代碼 }
-
構(gòu)造函數(shù)的作用: 對實(shí)例對象的內(nèi)容進(jìn)行初始化
- Swift要求類或者結(jié)構(gòu)體中的存儲屬性(非lazy的)在對象構(gòu)造完畢后要有初始化值, 因此經(jīng)常在構(gòu)造函數(shù)中對屬性初始化
-
注意:
- 1.在Swift中類/結(jié)構(gòu)體/枚舉都需要構(gòu)造方法
- 2.構(gòu)造方法的作用僅僅是用于初始化屬性, 而不是分配內(nèi)容, 分配內(nèi)存是系統(tǒng)幫我們做的
- 3.構(gòu)造方法是隱式調(diào)用的, 通過 類名稱() 形式創(chuàng)建一個對象就會隱式調(diào)用init()構(gòu)造方法
- 4.如果所有的存儲屬性都有默認(rèn)值, 可以不提供構(gòu)造方法, 系統(tǒng)會提供一個隱式的構(gòu)造方法
- 5.如果存儲屬性可以提供缺省, 那么提倡大家使用設(shè)置缺省值的方式, 這樣可以簡化代碼(不用自定義構(gòu)造方法, 不用寫存儲屬性類型)
2. 構(gòu)造函數(shù)使用
2.1 構(gòu)造函數(shù)的基本使用
- 類的屬性必須有值
- 如果不是在定義時初始化值,可以在構(gòu)造函數(shù)中賦值
class Person: NSObject {
var name : String
var age : Int
// 重寫了NSObject(父類)的構(gòu)造方法
override init() {
name = ""
age = 0
}
}
// 創(chuàng)建一個Person對象
let p = Person()
class Person { // 基類是自己本身
var name : String = ""
var age : Int = 0
// 如果沒有明確的實(shí)現(xiàn)默認(rèn)的init()函數(shù),那么擴(kuò)充構(gòu)造函數(shù)時,
// 會覆蓋默認(rèn)的init()構(gòu)造函數(shù), 就是在創(chuàng)建對象的時候沒有默認(rèn)的創(chuàng)建方式 : 類名()
init() {
// 這里重寫默認(rèn)的 init 方法, 可以什么都不做,
// 因?yàn)榍懊嬉呀?jīng)給所有的屬性初始化,
// 如果前面有屬性沒有被初始化, 則必須在構(gòu)造函數(shù)中做初始化
}
}
class Person {
var name:String = "cdh"
var age:Int
func description() -> String {
return "name = \(name) age = \(age)"
}
init(){
print("init")
// age 屬性在定義的時候沒有比初始化, 所以必須在這里做初始化
age = 20
}
}
//1.分配內(nèi)存
//2.初始化name和age
//3.構(gòu)造方法是隱式調(diào)用的 init()
var p = Person()
p.description() //顯示調(diào)用
//輸出結(jié)果: init
3. 自定義構(gòu)造函數(shù)
3.1 自定義構(gòu)造函數(shù)
- 很多時候,我們在創(chuàng)建一個對象時, 同時給對應(yīng)屬性賦值
- 可以自定義構(gòu)造函數(shù)
-
注意: 如果自定義了構(gòu)造函數(shù),又沒有重寫
init()
函數(shù), 則自定義的構(gòu)造函數(shù)會覆蓋默認(rèn)的 init()
方法.即不在有默認(rèn)的構(gòu)造函數(shù), 也就不能直接通過 類名()
創(chuàng)建對象
//帶參數(shù)的自定義構(gòu)造函數(shù)
class Person1 {
var name:String
var age:Int
func description() -> String{
return "name = \(name) age = \(age)"
}
//構(gòu)造方法的內(nèi)部參數(shù), 默認(rèn)也是外部參數(shù)
//而函數(shù)的內(nèi)部參數(shù)默認(rèn)不會當(dāng)做外部參數(shù)
//而普通的外部函數(shù)的參數(shù), 從第二個開始才會當(dāng)做外部參數(shù)
//Swift 3.0 之后默認(rèn)所有的參數(shù)即是外部參數(shù)又是內(nèi)部參數(shù)
//init(name:String, age:Int)
//構(gòu)造方法對屬性的順序沒有要求,
//只要保證對象構(gòu)造完時所有存儲屬性被初始化即可
init(age:Int, name:String) {
self.name = name
self.age = age
}
}
var p1 = Person1(age: 20, name: "cdh")
print("name : \(p1.name), age : \(p1.age)")
3.2 字典轉(zhuǎn)模型(初始化時傳入字典)
- 真實(shí)創(chuàng)建對象時,更多的是將字典轉(zhuǎn)成模型
-
注意:
- 去字典中取出的是NSObject,任意類型.
- 可以通過as!轉(zhuǎn)成需要的類型,再賦值(不可以直接賦值)
class Person: NSObject {
var name : String
var age : Int
// 自定義構(gòu)造函數(shù),會覆蓋init()函數(shù)
init(dict : [String : NSObject]) {
name = dict["name"] as! String
age = dict["age"] as! Int
}
}
// 創(chuàng)建一個Person對象
let dict = ["name" : "cdc", "age" : 18]
let p = Person(dict: dict)
3.3 字典轉(zhuǎn)模型(利用KVC轉(zhuǎn)化)
- 利用KVC字典轉(zhuǎn)模型會更加方便
- 必須繼承自NSObject
- 必須在構(gòu)造函數(shù)中先調(diào)用super.init()
-
注意1:
- KVC并不能保證會給所有的屬性賦值
- 因此屬性需要有默認(rèn)值
- 基本數(shù)據(jù)類型默認(rèn)值設(shè)置為0
- 對象或者結(jié)構(gòu)體類型定義為可選類型即可(可選類型沒有賦值前為nil)
- **注意2: **
- 如果傳入的字典中的鍵值對比當(dāng)前類中的鍵值對多, 則程序會直接奔潰
- 解決這種情況, 則需要重寫父類的 setValue 方法, 并且什么也不做
- 注意:
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
別寫錯了, 有多個 setValue 函數(shù), 區(qū)別在于參數(shù)不一樣
- 如果是對父類某一個函數(shù)進(jìn)行重寫,必須在函數(shù)前加上
override
class Person: NSObject {
// 結(jié)構(gòu)體或者類的類型,必須是可選類型.因?yàn)椴荒鼙WC一定會賦值
var name : String?
// 基本數(shù)據(jù)類型不能是可選類型,否則KVC無法轉(zhuǎn)化
var age : Int = 0
// 自定義構(gòu)造函數(shù),會覆蓋默認(rèn)的 init()函數(shù)
init(dict : [String : NSObject]) {
// 必須先初始化對象
super.init()
// 調(diào)用對象的KVC方法字典轉(zhuǎn)模型(這里沒有產(chǎn)生歧義的時候 self 可以省略)
// self.setValuesForKeysWithDictionary(dict)
setValuesForKeysWithDictionary(dict)
}
// 如果傳入的字典中的鍵值對比當(dāng)前類中的鍵值對多, 則程序會直接奔潰
// 解決這種情況, 則需要重寫父類的 setValue 方法
// 如果是對父類某一個函數(shù)進(jìn)行重寫,必須在函數(shù)前加上override
override func setValue(value: AnyObject?, forUndefinedKey key: String) {}
}
// 創(chuàng)建一個Person對象
let dict = ["name" : "cdc", "age" : 18]
let p = Person(dict: dict)
4. 屬性與構(gòu)造函數(shù)
4.1 常量存儲屬性與構(gòu)造方法
- 常量存儲屬性只能通過缺省值或在構(gòu)造方法中被修改
- 其它任何地方都不能修改, 并且只能被賦值一次
class Person2 {
var name:String = "cdh"
let age:Int
init(age:Int, name:String){
self.age = age
self.name = name
}
func description() ->String{
return "name = \(name) age = \(age)"
}
}
var p2 = Person2(age: 20, name:"Aarak")
print(p2.description())
//輸出結(jié)果: name = Aarak age = 20
//常量存儲屬性初始化之后不允許被修改, 下面寫法錯誤
//p2.age = 10
4.2 可選屬性與構(gòu)造函數(shù)
- 類屬性一般都是定義為可選屬性
- 可選值存儲屬性可以不再構(gòu)造方法中初始化,
- 也就是說可選值在對象構(gòu)造完畢后不用初始化
- 其實(shí)如果不對可選存儲屬性進(jìn)行初始化, 默認(rèn)就是nil
class Car {
let name:String
init(name:String){
self.name = name
}
}
class Person3 {
let name:String
var age:Int
var car:Car? // 類屬性一般都是定義為可選屬性
init(age:Int, name:String) {
self.age = age
self.name = name
}
func description() ->String{
return "name = \(name) age = \(age) car = \(car)"
}
}
var p3 = Person3(age: 10, name: "cdh")
print(p3.description())
//輸出結(jié)果: name = cdh age = 10 car = nil