构造过程

  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支持调用时候能够缺省有默认值的参数。 类中默认只有无参数的构造器。而且一旦写了自定义的构造器,那么结构体和类中的默认构造器将会失效。
相关文章
相关标签/搜索