美文网首页
2020-11-16 init 模式

2020-11-16 init 模式

作者: 脑子 | 来源:发表于2020-11-16 18:37 被阅读0次
//init方法,初始化所有存储属性,结构体是值类型,类是引用类型
struct Point {
    let x: Int
    let y: Int
    
    init(x: Int,y:Int) {
        self.x = x
        self.y = y
    }
}

let p1 = Point(x: 1, y: 1)
print(p1)

逐一成员构造器

//逐一成员构造器 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器
//只要结构体的任何一个存储属性是 private 的,那么结构体的默认逐一成员构造器也将是 private 的。同样,如果结构体的任何一个存储属性是 file private 的,那么逐一成员构造器也将是 file private 的。其他情况,这个构造器的访问级别是 internal

struct Point1 {
    let x: Int
    let y: Int
    var key: Int!
    let label: String? = "zero"
}
let p2 = Point1(x: 1, y: 2, key: 3)
print(p2)

失败构造器init?

//失败构造器,过滤掉一堆点里面的原点
struct Point2 {
    let x: Int
    let y: Int
    
    //问号标记构造器可能失败
    init?(x: Int, y: Int){
        if x == 0 && y == 0 {
            return nil
        }
        self.x = x
        self.y = y
    }
}

let p3 = Point2(x: 0, y: 0)
let p4 = Point2(x: 1, y: 5)

//枚举遵循RawRepresentable协议,他们可以通过rawValue来构造,也是失败构造器
enum Color: String {
    case red
    case blue
    case yellow
}

let c1 = Color(rawValue: "橘色") //nil
let c2 = Color(rawValue: "red") //red

初始化类

//初始化类,需要自己写init方法,类没有逐一成员构造器
class Point{
    let x: Int
    let y: Int
    
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

let p0 = Point(x: 1, y: 8)

//默认构造器
class Point1 {
    let x: Int = 1
    let y: Int = 4
}
let p1 = Point1()

class Point2 {
    let x: Int = 0
    let y: Int = 0
    var key: Int!
    let label: String? = "zero"
}
let p2 = Point2()

指定构造器

//初始化类,需要自己写init方法,类没有逐一成员构造器
class Point{
    let x: Int
    let y: Int
    
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}
//类继承 指定构造器
class NamedPoint: Point{
    let label: String?
    
    init(x: Int, y: Int, label:String?){ //指定构造器
        self.label = label
        
        super.init(x: x, y: y)
    }
    
    //Point里面有x y两个属性,所以必须初始化
    //注意,如果属性是隐式解包可选型属性,或者普通的可选型属性,并且它们同时是变量而非常量的话,你是可以不初始化它们的
    init(point: Point, label: String?){ //指定构造器
        self.label = label
        super.init(x: point.x, y: point.y) //向上代理
    }
}

let p1 = NamedPoint(x: 1, y: 1, label: "first")
let p2 = NamedPoint(point: Point(x: 1, y: 2), label: "second")

指定构造器必须调用它的直接父类的某个指定构造器,所以你需要向上代理构造链。但在这之前,根据初始化的第一条规则,我们必须先确保当前类的所有存储属性被初始化。这意味着 Swift 语言其实是有一个两段式构造过程。

两段式构造

类的每个存储属性都会由引入这个属性的继承层级赋予一个初始值。
类的每一个继承层级都被给予时机定制自己的存储属性。
基于这两条规则,首先我们必须初始化 label 属性,然后向上代理构造过程。完成这两步之后我们才能真正开始使用对象。

便利构造器convenience

//类的便利构造器,便利构造器必须调用同一个类层级里的其他构造器,最终调用到指定构造器
class Point{
    let x: Int
    let y: Int
    
    init(x: Int, y: Int){
        self.x = x
        self.y = y
    }
    convenience init(z: Int) {
        self.init(x: z, y: z) //其实是调用了xy的构造器
    }
}
let p1 = Point(z: 1)

//struct的便利构造器,不用写convenience
struct Point1{
    let x: Int
    let y: Int
    
    init(x: Int, y: Int){
        self.x = x
        self.y = y
    }
    init(z: Int) {
        self.init(x: z, y: z) //其实是调用了xy的构造器
    }
}
var p2 = Point1(z: 1)

必须构造器 required

//必须构造器 required,父类和子类都必须有required
class Point{
    let x: Int
    let y: Int
    
    required init(x: Int, y: Int){
        self.x = x
        self.y = y
    }
}

class NamedPoint: Point {
    let label: String?
    
    required init(x: Int, y: Int){
        self.label = nil
        
        super.init(x: x, y: y)
    }
}

let p1 = NamedPoint(x: 1, y: 1)

重写构造器override

//重写构造器,swift中构造器默认是不被子类继承的,如果想为子类提供一个父类已经存在的构造器,需要用override关键字
class Point {
    let x: Int
    let y: Int
    
    init(x: Int, y: Int){
        self.x = x
        self.y = y
    }
}

class NamedPoint: Point {
    let label: String?
    
    override init(x: Int, y: Int){
        self.label = nil
        
        super.init(x: x, y: y)
    }
}

let p1 = NamedPoint(x: 1, y: 2)
//构造器继承有两条规则:
//1,如果你的子类没有定义任何指定构造器,它将自动继承其父类的所有指定构造器。
//2,如果你的子类提供其父类的指定构造器的实现——无论是通过规则1继承得到,或者自定义实现的,那么它都会自动继承父类的所有便利构造器。

相关文章

网友评论

      本文标题:2020-11-16 init 模式

      本文链接:https://www.haomeiwen.com/subject/wtczbktx.html