swift 类、结构体和枚举的初始化(三)

这是我参与更文挑战的第17天,活动详情查看: 更文挑战

可失败的初始化方法

  • 可失败的初始化方法:当初始化方法传入无效的参数值,或缺少某种所需的外部资源、或不满足某种必要的条件
  • 类、结构体和枚举使用关键字init?定义可失败的初始化方法
class Student {
    var name: String
    init? (name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}
复制代码
  • 可以用init!定义隐式解包的可失败初始化方法

  • 不允许同时定义参数标签、参数个数、参数类型相同的可失败初始化和非可失败初始化方法

  • 可失败初始化方法可以调用非可失败初始化方法,非可失败初始化方法调用可失败初始化方法需要进行解包

  • 如果初始化调用一个可失败初始化方法导致初始化失败,那么整个初始化过程都是失败的,并且之后的代码都停止执行

class ClassA{
    let str:String!
    init?(str:String) {
        if str.isEmpty{
            return nil
        }
        self.str = str
    }
}

class ClassB:ClassA{
    let b:Float
    init?(a:String,b:Float) {
        if b<1 {
            return nil
        }
        self.b = b
        super.init(str: a)
    }
}

let c = ClassB.init(a: "1", b: 0)   //nil
let d = ClassB.init(a: "", b: 1)   //nil
let e = ClassB.init(a: "1", b: 1)  //ClassB
复制代码
  • 可以用非可失败初始化方法重写一个可失败初始化方法,但是反过来不行

重写可失败初始化

可以用一个不可失败的初始化重新父类可失败初始化,但是不能反过来,重写父类初始化时,返回值要强制解包

class ClassA{
    var str:String
    init?(str:String) {
        self.str = str
        if str.isEmpty{
            return nil
        }
    }
}

class classC:ClassA{
    var c:String
    override init(str: String) {
        c = str
        super.init(str: str)!
    }
}
let cc = classC.init(str:"d")  //classC
复制代码

init!可失败初始化

init?需要解包,init!直接使用
不管使用哪种形式,都需要判空


必要初始化

如果初始化用required来修饰,那么意味着子类必须重写该父类的构造器

class ClassA{
    var str:String
    required init(str:String){
        self.str = str
    }
}

class classC:ClassA{
    var c:String
    required init(str: String) {
        c = str
        super.init(str: c)
    }
}
let cc = classC.init(str: "c") //classC

复制代码

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

class ClassA{
    var str:String
    required init(){
        str = "0"
    }
}

class classC:ClassA{
    var c = "1"
}
let cc = classC.init() //classC
复制代码

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

在设置存储属性默认值时,可以用函数或者闭包来实现

class SomeClass {
    let someProperty: SomeType = {
        // 注意: 在这里不能用self, 更不能用其它的属性(即使它有默认值, 因为self还没准备好)或者该类的实例方法,执行这段代码时, 初始化都还没有进行

        // 在这个闭包中给 someProperty 创建一个默认值
        // someValue 必须和 SomeType 类型相同
        return someValue
    }()// 最后要加上(), 不然就被当做是个闭包, 而不是这个闭包的结果了
}
复制代码
struct Checkerboard {
    let boardColors: [Bool] = {
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
        return boardColors[(row * 8) + column]
    }
}
复制代码

每当一个新的Checkerboard实例被创建时,赋值闭包会被执行,boardColors的默认值会被计算出来并返回。上面例子中描述的闭包将计算出棋盘中每个格子对应的颜色,并将这些值保存到一个临时数组temporaryBoard中,最后在构建完成时将此数组作为闭包返回值返回。这个返回的数组会保存到boardColors中,并可以通过工具函数squareIsBlackAtRow来查询:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享