構造過程

  1. 定義屬性的三種方式
    1. 直接賦初始值
    2. 只寫類型,在構造器中賦初始值
    3. 當前是缺省值,之後必定有值。或者當前是缺省值,之後可能仍是缺省值。
class Test {
    //給屬性賦默認值
    var a = 0
    //給屬性類型,默認值在構造器中賦值
    var b: Int
    //當前是缺省值,
    var c: Int?//當前是缺省值,之後可能仍是缺省值
    var d: Int!//當前是缺省值,之後必定有值
    
    init(b: Int) {
        self.b = b
    }
}
複製代碼
  1. 構造器簡單使用
struct Color {
    var red: Double, green: Double, blue: Double
    
    init(red: Double, green: Double, blue: Double) {
        self.red = red;
        self.green = green
        self.blue = blue
    }
    
    init(white: Double) {
        self.red = white
        self.green = white
        self.blue = white
    }
}

var aColor = Color(red: 1.0, green: 0, blue: 0)
var bColor = Color(white: 0.5)
print("aColor: \(aColor)")
print("bColor: \(bColor)")
複製代碼
  1. 結構體的逐一成員構造器
    1. 結構體和類都有一個默認的無參數的構造器。
    2. 結構體比類多了一個默認的逐一成員構造器。
    3. 結構體的逐一成員構造器調用時候能夠省略有默認值的參數。(swift5.1最新版本更新的內容)
struct Test {
    var a = 3
    var b = 5
}

var a = Test(a: 3, b: 6)
var b = Test(a: 5)
print(a)
print(b)
複製代碼
  1. 當咱們在類或者結構體中寫了自定義的構造器後,默認的構造器將消失。swift

  2. 類的構造器構造過程
    構造過程分爲兩個階段bash

    階段一:閉包

    1. 首先便利構造器調用本類的指定構造器。
    2. 本類的指定構造器先初始化本類的屬性,以後再調用父類的指定構造器。
    3. 父類的指定構造器再次初始化自身的屬性,以後再次調用它的父類的指定構造器。
    4. 這樣就指定構造器就沿着它的繼承鏈向上代理,直到最頂部。這時候完成了整個類的初始化。

    階段二:app

    1. 當指定構造器向上代理到最頂部時候,接下來要向下代理,進行第二階段
    2. 接下來沿着指定構造器的繼承鏈向下執行自定義部分(可能沒有)
    3. 最後到達了遍歷構造器處,這時候已經徹底初始化了本類的全部屬性。以後就可使用這些屬性了。
class Test {
    var a: Int
    
    init(a: Int) {
        print("Test-init-start")
        self.a = a
        print("Test-init-end")
    }
}
class Test1: Test {
    var b: Int
    
    init(b: Int, a: Int) {
        print("Test1-init-start")
        self.b = b
        super.init(a: a)
        print("Test1-init-end")
    }
}


class Test2: Test1 {
    var c: Int
     init(c:Int, b: Int, a: Int) {
        print("Test2-init-start")
        self.c = c
        super.init(b: b, a: a)
        print("Test2-init-end")
    }
    
     convenience init(){
        //階段一與階段二:利用指定構造器完成整個類的屬性初始化
        print("階段一:調用指定構造器沿着繼承鏈向上完成屬性的初始化 階段二:在從鏈頂向下完成自定義部分")
        print("convenience init")
        self.init(c: 0, b: 0, a: 0)
        
        //最後到達遍歷構造器,這時候能夠徹底訪問屬性了
        let d = (a + 1) * (b + 2) * (c + 3)
        print(d)
    }
}

//var test = Test2(c: 1, b: 2, a: 3)
var test1 = Test2()

//打印以下:
//階段一:調用指定構造器沿着繼承鏈向上完成屬性的初始化   階段二:在從鏈頂向下完成自定義部分
//convenience init
//Test2-init-start
//Test1-init-start
//Test-init-start
//Test-init-end
//Test1-init-end
//Test2-init-end
//6
複製代碼
  1. 結構體中的構造器ide

    1. 結構體中只有指定構造器,且沒有繼承鏈。
    2. 類中有指定構造器,還有遍歷構造器,還有繼承鏈。相對更復雜些。
  2. 構造器的繼承和重寫ui

    1. 若是子類不寫任何指定構造器(包括自定義的和父類的),這時候子類將繼承全部父類的構造器(包括父類的指定構造器和父類的便利構造器)
    2. 若是子類把父類的全部指定構造器都重寫了,那麼這時候子類將會繼承父類的全部構造器,主要是父類的遍歷構造器。
    3. 若是子類繼承了父類的全部構造器,那麼這個時候子類能夠選擇性的重寫父類的遍歷構造器,而且前邊不用加關鍵在override。
  3. 構造器便利構造器的使用spa

class Food {
    var name: String
    
    init(name:String) {
        self.name = name
    }
    
    convenience init(){
        self.init(name: "Unnamed")
    }
}

class Material: Food {
    var count: Int
    
    init(count: Int, name: String) {
        self.count = count
        super.init(name: name)
    }
    
    convenience override init(name: String) {
        self.init(count:1, name:name)
    }
}

class ShoppingListItem: Material {
    var purchased = false
    func description() {
        let purchas = purchased ? " ✔" : " ✘"
        print("\(count) X \(name) \(purchas)")
    }
}

let listItem = [ShoppingListItem(), ShoppingListItem(name: "麪包"), ShoppingListItem(count: 5, name: "巧克力")]
listItem[1].purchased = true
listItem[0].description()
listItem[1].description()
listItem[2].description()
複製代碼
  1. 可失敗構造器
    1. 當在給一個構造器傳入非法入參時候,這時候沒辦法給屬性賦值,這時候就能夠用可失敗構造器。
    2. 在可失敗構造器內部判斷非法入參,返回nil就是構造失敗了。
struct Animal {
    let species: String
    init?(species: String){
        if species.isEmpty {
            return nil
        }
        self.species = species
    }
}

var a = Animal(species: "")
if a == nil{
    print("構造失敗")
}else{
    print("構形成功:" + a!.species)
}
//打印以下
//構造失敗
複製代碼
  1. 枚舉類型下的可失敗構造器
enum Direction: Character {
    case D = "D", X = "X", N = "N", B = "B"

    init?(direction: Character){
        switch direction {
        case "D":
            self = .D
        case "X":
            self = .X
        case "N":
            self = .N
        case "B":
            self = .B
        default:
            return nil
        }
    }
}

var a = Direction(direction: "D")
print(a!.rawValue)

if let a = Direction(direction: "T") {
    print("可選枚舉構形成功:\(a.rawValue)")
}else{
    print("可選枚舉構造失敗")
}
複製代碼
  1. 原始值枚舉類型構造器是一個可失敗的構造器
enum Direction: Character {
    case D = "D", X = "X", N = "N", B = "B"
}

if let a = Direction(rawValue: "T") {
    print("可選枚舉構形成功:\(a.rawValue)")
}else{
    print("可選枚舉構造失敗")
}
複製代碼
  1. 構造失敗向上代理
class Product {
    var name: String
    init?(name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}

class CartItem: Product {
    var count: Int
    init?(name: String, count: Int) {
        if count < 1 {
            return nil
        }
        self.count = count
        
        super.init(name: name)
    }
}

if let a = CartItem(name: "2", count: 10){
    print("構形成功: \(a.name) \(a.count)")
}else{
    print("構造失敗")
}
複製代碼
  1. 可失敗構造器的繼承和重寫
    1. 不可失敗構造器能夠重寫父類的不可失敗構造器。
    2. 可失敗構造器能夠重寫父類的可失敗構造器。
    3. 不可失敗構造器能夠重寫父類的可失敗構造器,這時候每每在內部要調用父類的不可失構造器。若是調用那個被重寫的可失敗構造器,那麼就要強制解包,這有可能會發生運行時錯誤。
    4. 可失敗構造器不可以重寫父類的不可失敗構造器。
class Product {
    var name: String?
    init() {}
    
    init?(name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}

class CartItem: Product {
    override init() {
        super.init()
        self.name = "Unnamed"
    }
    
    override init(name: String) {
        super.init()
        if self.name == nil {
            self.name = "Unnamed"
        }
    }
}

var a = CartItem(name: "")
print(a.name!)
複製代碼
  1. 必要構造器
    1. 必要構造器就是在init前邊加上關鍵字requird。
    2. 當子類繼承了父類全部構造器後,子類就沒必要重寫父類的必要構造器。
    3. 當子類沒有繼承父類的全部構造器的時候,子類必需要重寫父類的必要構造器,繼續在init方法前邊加上requird關鍵字,沒必要加override關鍵字。
class Product {
    var name: String
    required init(name: String) {
        self.name = name
    }
}

class CartItem: Product {
    var sex: Int = 1
    //當該類繼承了父類全部構造器的時候,就沒必要重寫父類的必要構造器
    //當該類沒有繼承父類的全部構造器的時候,就要重寫父類的必要構造器
    init(sex: Int, name: String) {
        self.sex = sex
        super.init(name: name)
    }
    
    required init(name: String) {
        self.sex = 0
        super.init(name: name)
    }
}

var a = CartItem(name: "s")
print(a.name)
複製代碼
  1. 利用閉包完成屬性的初始化
class Squire {
    //經過閉包馬上給屬性初始化
    let colorSquire: [Bool] = {
        var tempArr = [Bool]()
        var isBlack = false
        for _ in 1...8{
            for _ in 1...8{
                tempArr.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        
        return tempArr
    }()
    
    //計算屬性
    var squireCount: Int {
        return colorSquire.count
    }
    
    //下標
    subscript(row: Int, col: Int) -> Bool{
        return colorSquire[row * 8 + col]
    }
    
    
    func squireColor(row: Int, col: Int) -> Bool {
        return colorSquire[row * 8 + col]
    }
}

var a = Squire()
print(a.squireColor(row: 2, col: 2))
print(a[2,2])
複製代碼
  1. 計算屬性,下標,閉包初始化屬性比較代理

    1. 計算屬性
      1. 寫法是var name:Type{}
      2. 若是不須要setter方法就能夠省略關鍵字get。get的實現是必須的。
      3. 計算屬性是經過其餘的存儲屬性計算獲得的屬性。
    2. 下標
      1. 寫法是subscript(參數) -> type{}
      2. 若是不須要setter方法就能夠省略關鍵字get。get的實現是必須的。
    3. 閉包初始化屬性
      1. 寫法是var name:type = {}()
      2. 若是不須要setter方法就能夠省略關鍵字get。get的實現是必須的。
    4. 比較
      1. 計算屬性目的是其餘存儲屬性計算獲得。{}不是等於號,不用馬上執行。
      2. 下標的目的是經過下標來訪問成員。寫法是必需要有關鍵字寫法是subscript,subscript(參數) -> type{}。
      3. 閉包初始化屬性,目的是馬上經過一些邏輯來完成屬性的初始化,{}要有等於號,是建立實例對象時候馬上執行的()。
  2. 計算屬性,下標,閉包初始化屬性使用場景code

    1. 該屬性要經過一些存儲屬性的計算獲得,這時候要用計算屬性。
    2. 該對象要經過下標來訪問內部數據,要用下標。
    3. 若是建立對象時候就要進行一些邏輯計算等來建立一個屬性,就用閉包來初始化這個屬性。
  3. 總結對象

    1. 結構體中只有指定構造器,沒有遍歷構造器。使用時候就是在init方法內部初始化本類屬性便可。
    2. 類中既有指定構造器還有遍歷構造器
      1. 指定構造器是先初始化本類屬性,以後調用父類構造器。最後修改父類屬性。
      2. 遍歷構造器內部必定要先調用本類的指定構造器,完成全部屬性初始化後再去用這些屬性。
    3. 類中構造器的繼承
      1. 子類中若是一個指定構造器都沒有寫,那麼子類會繼承父類的所有構造器(包括父類的指定構造器和遍歷構造器)
      2. 子類若是重寫了父類的全部指定構造器(能夠把父類的指定構造器重寫成遍歷構造器),那麼子類會自動繼承父類的全部構造器(包括父類的指定構造器和遍歷構造器)
      3. 當子類自動繼承了父類的全部構造器後,子類能夠選擇性的重寫父類的遍歷構造器,而且不用使用override關鍵字。
    4. 結構體中默認有無參數的構造器和成員逐一構造器,而且swift5.1支持調用時候能夠缺省有默認值的參數。 類中默認只有無參數的構造器。而且一旦寫了自定義的構造器,那麼結構體和類中的默認構造器將會失效。
相關文章
相關標籤/搜索