为什么默认情况下会调用超类指定的初始化程序?

时间:2016-06-30 11:23:15

标签: ios swift oop inheritance

我是Swift的新手并且在初始化程序方面遇到了一些问题。我用以下代码创建了一个Swift文件:

if(1){       
   function foo(){
      echo 'foo!';
   }
   foo(); // No errors, since function is defined!
}

在上面的代码中,if($IsLoggedIn){ // include files/functions and bootstrap here... } 的{​​{1}}不包含对import Foundation class SuperClass { var a : Int init() { a = 10 print("In Superclass") } } class SubClass : SuperClass { override init() { print("In Subclass") } } 的{​​{1}}的调用,即init()中没有SubClass

所以我的问题是:

  1. 如果我不拨打init()

    指定的SuperClass
  2. ,为什么不会出现任何错误
  3. 如果我正在创建super.init()的对象,即SubClass init(),则输出为:

    在子类

    超级课程

  4. 为什么要调用init()的{​​{1}}?子类init()默认调用超类init()吗?

5 个答案:

答案 0 :(得分:1)

据我了解你的问题,你不仅想知道为什么,何时以及如何自动调用初始化程序,而且还抱怨缺少这种行为的文档。

首先,我同意你的观点是缺乏文档 - 就像你一样,我无法找到有关此行为的任何内容,因此应将其添加到Apple的文档中。

为什么调用super.init()

根据文档,超类的指定初始值设定项必须由其子类的指定初始值设定项调用,以便完全初始化所有属性。

  

规则1

     

指定的初始化程序必须从其中调用指定的初始化程序   直接超类。

上面的代码示例证明它显然是隐式完成的:print("In Superclass")打印到控制台,因此在创建实例时会以某种方式调用super.init()

调用super.init()的时间和方式:

为了允许编译器隐式调用超类的指定初始值设定项,需要满足一些条件:

  1. 超类必须只有一个指定的初始化程序 然后被叫。否则编译器必须选择一个委托 至。这个单一的指定初始化程序也可以是默认值 初始化器或继承的初始化器。

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
        // introduction of a second designated initializer in superclass:
        init(withValue value: Int) {
            a = value
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: super.init isn't called on all paths before returning from initializer"            
        override init() {}
    }
    
  2. 超类的单个指定初始值设定项不能有任何 参数。毕竟编译器不会知道任何合适的 要传递的参数。

    class SuperClass {
        var a: Int
        // declaration of an initializer with parameter:
        init(withValue value: Int) {
            a = value
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: super.init isn't called on all paths before returning from initializer"            
        override init() {}
    }
    
  3. 子类的指定初始值设定项不得进一步读取或 修改(继承)超类或调用的实例属性 超类的实例方法。那是因为斯威夫特的 两阶段初始化过程及其相应的安全性 检查和隐含委托达到指定的事实 超类的初始化程序发生在结束时 init - 子类中的语句。

      

    安全检查2

         

    指定的初始值设定项必须最多委托给a   在为继承的值赋值之前的超类初始化程序   属性。如果没有,则新值指定初始化程序   分配将被超类覆盖,作为其自身的一部分   初始化“。

         

    安全检查4

         

    初始化程序无法调用任何实例方法,读取   任何实例属性的值,或将self称为值   直到初始化的第一阶段完成之后。

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: use of 'self' in property access 'a' before super.init initializes self"            
        override init() {
            a = 10 // modifying inherited self.a before phase 1 of initialization completes isn't valid! 
            // implicit delegation to super.init()
        }
    }
    
      

    安全检查1

         

    指定的初始化程序必须确保所有的   它的类引入的属性在它之前被初始化   委托一个超类初始化器。

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
    }
    
    class SubClass: SuperClass {
        // introduction of instance property "b"
        var b: Int
        // compiles finely:
        override init() {
            b = 10 // initializing self.b is required before delegation!
            // implicit delegation to super.init()
        }
    }
    
  4. 我希望有所帮助。

答案 1 :(得分:1)

  

为什么要调用SuperClass的init()?子类init()默认调用超类init()吗?

基本上,是的。

如果所有规则都说你应该说super.init()并且你没有说出来,那就是为你而来。

我不喜欢这种行为;它的记录很少,此外,暗中为你做的事似乎违背了斯威夫特的精神。但是我很久以前就提出了一个针对它的错误,并被告知这是预期的行为。

答案 2 :(得分:0)

您没有访问子类中的超类变量,因此调用了super.init(),后跟子类的init。但是,如果您尝试在子类中使用超类变量而不调用其初始化器,则会导致编译时错误。

答案 3 :(得分:0)

我自己没有尝试过,但Swift Language Guide说:

  

类类型的初始化程序委派

     

为简化指定和便利初始值设定项之间的关系,Swift在初始值设定项之间应用以下三个规则进行委托调用:

     

规则1

     

指定的初始值设定项必须从其直接超类中调用指定的初始值设定项。

     

规则2

     

便捷初始化程序必须从同一个类调用另一个初始值设定项。

     

规则3

     

便捷初始化程序必须最终调用指定的初始化程序。

     

记住这一点的一个简单方法是:

     

指定的初始值设定项必须始终委派。

     

便利初始化程序必须始终委派。

因此,调用super.init()是一个“规则”,如果没有明确实现,它可能只是在内部完成。

答案 4 :(得分:0)

每个类至少有一个指定的初始化程序,它负责初始化实例变量。

以下是doc:

的摘录
  

类往往只有很少的指定初始值设定项,并且一个类只有一个很常见。指定的初始化器是初始发生的“漏斗”点,初始化过程通过该点继续超级链。

     

每个班级必须至少有一个指定的初始化程序。在某些情况下,通过从超类继承一个或多个指定的初始值设定项来满足此要求,如下面的Automatic Initializer Inheritance中所述。

有关详细信息,请参阅完整文档:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

经验法则

  1. 为您的班级创建一个指定的初始值设定项。
  2. 调用超类的指定初始值设定项或让系统为您解决此问题。
  3. 创建零个或多个便利初始化程序,它们将调用您指定的初始化程序。