Swift开发--Designated、Convenience和Required

开篇

在今天之前,我一直是不愿意写博客的,感觉写博客有些浪费时间,(其实这都是借口,主要还是因为懒想多玩局LOL,想多看个电影)正所谓一入坑门深似海,从此游戏成路人啊~

摘要

摘要:Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化。

进入正题

swift为什么要这样做呢?因为在OC中init方法不那么安全,没有人可以保证init只被调用一次,也没有人能保证在初始化之后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有开发者犯这样的错。
所以swift规定了严格的初始化方法,强化了designated初始化方法的地位。swift中不加修饰的init方法都需要在方法中保证所有非可选( Optional)的实例变量被赋值初始化,而在子类中也强制调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

class ClassA {
    let numA: Int
    init(num: Int) {
        numA = num
    }
}

class ClassB: ClassA {
    let numB: Int

    override init(num: Int) {//重写父类的方法
        numB = num + 1
        super.init(num: num)
    }
}

在上面的示例代码中,注意init里我们可以对let的实例变量进行赋值,这是初始化方法的重要特点。在swift中let声明的值是常量,无法被写入赋值,这对构建线程安全的API十分有用。因为swift中init只被调用一次,所以在init中我们可以为常量进行赋值,不用担心引起线程安全的问题。

与designated初始化相对应的是在init前加上convenience 关键字的初始化方法,这是swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。

class ClassAA {
    let numA: Int
    init(num: Int) {
        numA = num
    }
    convenience init(bigNum: Bool) {
        self.init(num: bigNum ? 10000 : 1) // 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置
    }
}

class ClassBB: ClassAA {
    let numB: Int
    override init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

只要在子类中实现重写了父类的convenience方法所需要的init方法的话,我们在子类中就可以使用父类的convenience初始化方法了。例如上面的代码中,我们在ClassB里实现了init(num:Int)的重写。这样,即使在ClassB中没有bigNum版本的convenience init(bigNum:Bool),我们依然可以用这个方法来完成子类的初始化

let anObj = ClassB(bigNum: true)  
// 输出结果:anObj.numA = 10000, anObj.numB = 10001

总结一下,初始化方法永远遵循下面两条原则

  • 初始化路径必须保证对象完全初始化,这样可以通过调用本类型的designated初始化方法来得到保证;
  • 子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。

对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样做的最大好处是可以保证依赖于某个designated初始化方法的convenience一直被调用。

class ClassAAA {
    let numA: Int
    required init(num: Int) {
        numA = num
    }
    required convenience init(bigNum: Bool) {
        self.init(num: bigNum ? 10000 : 1)
    } }
class ClassBBB: ClassAAA {
    let numB: Int
    required init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}
let sencondObj = ClassBB(bigNum: true)
print(sencondObj.numA, sencondObj.numB)

//输出结果 10000 10001

第一次写,还请码友们多多支持 谢谢!!

参考

DESIGNATED,CONVENIENCE 和 REQUIRED

你可能感兴趣的:(Swift开发--Designated、Convenience和Required)