iOS-swiftiOS Developer首页投稿(暂停使用,暂停投稿)

Swift3.0 构造过程整理

2016-12-30  本文已影响101人  bluajack

构造过程

构造器

//最简形式
init() {
    
    //此处进行构造过程

}

注意:Swift的构造器无需返回值,OC有

存储属性的初始赋值

//示例代码:
struct Test {

   let attribute = "bluajack"
   
}

struct Test {

    let attribute: String
    
    init(value: String) {
    
        //attribute = "bluajack"
        attribute = value
        
    }

}
let t = Test(value: "bluajack")
  1. 枚举是没有存储属性的,但是有计算属性。2.常量属性(let声明)一旦赋值后,就不能更改了。在本类的常量属性,其子类也不能修改这个常量属性。

默认构造器

//示例:
class Person {

    let name = "bluajack"
    
    var sex: String?//可选属性默认值为nil
    
}
let p = Person() //默认构造器 init(){}

结构体的逐一成员构造器

//示例
struct Test {

    let attribute = "bluajack"
    let attribute2: String
}
let t = Test(attribute2: "sb")
//范例1
struct Test {
    
    let attribute = "bluajack"
    let attribute2: String
    
}

//1.结构体test的存储属性全用常量声明
//2.存储属性中有属性没有赋初始值

//结果
let t = Test(attribute2: "sb")
//自动生成一个逐一成员构造器,但只有attribute2参数

//范例2
struct Test2 {
    
    let attribute = "bluajack"
    let attribute2: String = "sb"

}

//1.结构体test的存储属性全用常量声明
//2.存储属性全部赋值完毕

//结果
let t2 = Test2()
//没有生成逐一成员构造器,只有生成了默认的构造器

//范例3
struct Test3 {
    
    var attribute = "bluajack"
    var attribute2: String = "sb"
    
}

//1.结构体test的存储属性全用变量声明
//2.存储属性全部赋值完毕

//结果
let t3 = Test3(attribute: "s", attribute2: "b")
let t_3 = Test3()
//生成了逐一成员构造器,并且所有参数都存在,同时也生成了默认构造器

//范例4
struct Test4 {
    
    var attribute = "bluajack"
    var attribute2: String
    
}
//1.结构体test的存储属性全用变量声明
//2.存储属性中有属性没有赋初始值

//结果
let t4 = Test4(attribute: "s", attribute2: "b")
//生成了逐一成员构造器,并且所有参数都存在,但没有生成默认构造器

//范例5
struct Test5 {
    
    let attribute = "bluajack"
    var attribute2: String
    
}

let t5 = Test5(attribute2: "sb")

//范例6
struct Test6 {
    
    var attribute = "bluajack"
    let attribute2: String
    
}

let t6 = Test6(attribute: "s", attribute2: "b")

总结:结构体未提供自定义构造器 ->「 存在变量属性 -> 生成
                              不存在变量属性「 常量属性全部赋值 ->不生成
                                            存在常量属性未赋值 -> 生成
                                            」

值类型的构造器代理

千万记住,这种横向代理,只对值类型有效,类类型无效,类型有自己的规则。

//示例

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
//第三个Rect构造器init(center:size:)。它先通过center和size的值计算出origin的坐标,
//然后再调用(或者说代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中。

注意:假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中。

指定构造器

便利构造器


class A {

    var a:String
    
    //指定构造器
    init() { a = "123"}
    
    //便利构造器
    convenience init(value: String) {
    
        self.init()
    }

}

class B:A {

    //指定构造器
    init(hah: String) {
        
        
//        super.init()
        
//        a = hah
        
        //如果我们不需要改变a的话,我们可以不用显示的调用super.init()
        //因为这里是初始化的最后了,Swift替我们自动完成了。不过我一般还是加上,看的顺眼
    
    }


}

let b = B(hah: "567657")
print(b.a)

类的构造器代理

总儿言之,言儿总之
指定构造器必须总是向上代理
便利构造器必须总是横向代理

initializerDelegation01_2x.png

二段式构造过程

twoPhaseInitialization01_2x.png twoPhaseInitialization02_2x.png

构造器的继承和重写

class C {
    
    init(a: String) {print("?")}

    init(b: String) {}
}

class D:C {
    
    override init(a: String) {
    
        super.init(a: a)
        
    }
    override convenience init(b: String) {
    
        self.init(a: b)
        
    }

}

构造器的自动继承

规则1:如果子类没有定义任何指定构造器,它将自动继承父类的所有指定构造器。
规则2:如果子类提供了所有父类的指定构造器的实现,还是自定义重写提供了实现(将父类的指定构造器重写为便利构造器也可以)————它将自动继承父类所有的便利构造器。

可失败构造器

注意:可失败构造器不能与其他非可失败构造器同名。

注意:严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用return nil 表明可失败构造器构造失败,而不要用关键字return来表明构造成功。

struct Person {
    let name: String
    init?(value: String) {
        if value.isEmpty { return nil }
        name = value
    }
}

let p = Person(value: "bluajack")
//p的类型是 Person?而不是Person

if let someone = p {
    print("一个名为\(someone.name)的Person对象被创建成功了!")
}

let p2 = Person(value: "")
//p2的类型是 Person?而不是Person

if p2 == nil {
    print("Person对象初始化失败")
}

枚举类型的可失败构造器

enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
    init?(value: Character) {
        switch value {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}

let a = TemperatureUnit(value: "F")
if a != nil {
    print("这是一个定义温度的单位,所以初始化成功")
}

let unknownUnit = TemperatureUnit(value: "X")
if unknownUnit == nil {
    print("这不是一个定义温度的单位,所以初始化失败")
}

带原始值的枚举类型的可失败构造器

⚠️:带原始值的枚举类型会自带一个可失败构造器( init?(rawValue:) ),该可失败构造器有一个名为rawValue的参数,其类型和枚举类型的原始值的类型一致。

enum Temperatureunit2: Character {
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}

let b = Temperatureunit2(rawValue: "F")
if b != nil {
    print("这是一个定义温度的单位,所以初始化成功")
}

let unknownunit = Temperatureunit2(rawValue: "X")
if unknownunit == nil {
    print("这不是一个定义温度的单位,所以初始化失败")
}

构造失败的传递

注意:可失败构造器也可以代理到其他的非可失败构造器。通过这种方式,你可以增加一个可能的失败状态到现有的构造过程中。可失败构造器和类的构造器自动继承规则一样。

class Product {
    let name: String
    init?(value: String) {
        if value.isEmpty { return nil }
        name = value
    }
}

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

重写一个可失败构造器

注意:子类的非可失败构造器重写父类的可失败构造器时,向上代理到 父类的可失败构造器的唯一方式是 对父类的可失败构造器的返回值进行强制解包。

注意:非可失败构造器可以重写可失败构造器,反过来不行。

class Document {
    var name: String?
    // 该构造器创建了一个 name 属性的值为 nil 的 document 实例
    init() {}
    // 该构造器创建了一个 name 属性的值为非空字符串的 document 实例
    init?(value: String) {
        if value.isEmpty { return nil }
        name = value
    }
}

class AutoDocument: Document {
    override init() {
        super.init()
        name = "[Untitled]"
    }
    override init(value: String) {
        super.init(value: value)!
    }
}

let d = AutoDocument(value: "")
//发生运行时错误

必要构造器

class SomeClass {
    required init() {
        // 构造器的实现代码
    }
}

class SomeSubclass: SomeClass {
    required init() {
        // 构造器的实现代码
    }
}

注意:如果子类继承的构造器能满足必要构造器的要求,则无须在子类的必要构造器中显式提供父类必要构造器的实现

通过闭包或函数设置属性的默认值

class SomeClass {
    let someProperty: SomeType = {
        // 在这个闭包中给 someProperty 创建一个默认值
        // someValue 必须和 SomeType 类型相同
        return someValue
    }()
}

注意闭包结尾的大括号后面接了一对空的小括号。这用来告诉 Swift 立即执行此闭包。如果你忽略了这对括号,相当于将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。

注意:如果你使用闭包来初始化属性,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能在闭包里访问其它属性,即使这些属性有默认值。同样,你也不能使用隐式的self属性,或者调用任何实例方法。

OVER

上一篇 下一篇

猜你喜欢

热点阅读