当前位置 > 主页 > 万和大讲堂 >


南京iOS开发培训机构 Swift的初始化方法

2015-07-06 14:52

    Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化。

 

  而在子类中,也强制调用super版本的designated初始化。

 

  我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的。

 

  其实就是安全。在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。南京iOS开发培训机构

 

  所以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。

 

  Cpp代码

 

  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的方式被调用的。南京iOS开发培训机构

 

  Cpp代码

 

  class ClassA {

 

  let numA: Int

 

  init(num: Int) {

 

  numA = num

 

  }

 

  convenience init(bigNum: Bool) {

 

  self.init(num: bigNum ? 10000 : 1)

 

  }

 

  }

 

  class ClassB: ClassA {

 

  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),我们仍然还是可以用这个方法来完成子类初始化:

 

  Cpp代码

 

  let anObj = ClassB(bigNum: true)

 

  // anObj.numA = 10000, anObj.numB = 10001

 

  因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:南京iOS开发培训机构

 

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

 

  子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。

 

  对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。一个现成的例子就是上面的init(bigNum: Bool):如果我们希望这个初始化方法对于子类一定可用,那么应当将init(num: Int)声明为必须,这样我们在子类中调用init(bigNum: Bool)时就始终能够找到一条完全初始化的路径了:南京iOS开发培训机构

 

  Cpp代码

 

  class ClassA {

 

  let numA: Int

 

  required init(num: Int) {

 

  numA = num

 

  }

 

  convenience init(bigNum: Bool) {

 

  self.init(num: bigNum ? 10000 : 1)

 

  }

 

  }

 

  class ClassB: ClassA {

 

  let numB: Int

 

  required init(num: Int) {

 

  numB = num + 1

 

  super.init(num: num)

 

  }

 

  }

 

  另外需要说明的是,其实不仅仅是对designated初始化方法,对于convenience的初始化方法,我们也可以加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会非常有帮助。


最近开班 more>
  • Python基础班
  • Java全栈开发
  • 前端基础班
  • 软件测试
  • 云原生精英班
  • 云网预科班
  • CISP
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • OCM 12C
  • OCP 19C
  • RHCE 9.0
  • 随时开课
  • 12月26日
  • 随时开课
  • 12月4日
  • 12月16日
  • 12月9日
  • 12月21日
  • 1月6日
  • 12月30日
  • 12月16日
  • 12月21日
  • 12月7日
  • 12月7日
  • ——
  • 随时开课
  • 12月16日
    • 姓 名 :
    • 电 话 :
    • 课 程 :

技术交流群

  • Java大数据交流群560819979加入
  • Python技术交流群595083299加入
  • Oracle技术交流群595119011加入
  • Web前端技术交流群604697610加入
  • Huawei技术交流群482919361加入
  • Redhat技术交流群587875348加入
  • UI设计技术交流群511649801加入
  • Cisco技术交流群596886705加入
  • IT运维技术交流群605888381加入