Initialization构造函数(一)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Initialization构造函数(一)相关的知识,希望对你有一定的参考价值。

参考技术A Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.

初始化是准备要使用的类、结构或枚举的实例的过程。这个过程涉及为该实例上存储的每个属性设置一个初始值,并在新实例准备好使用之前执行任何其他设置或初始化。

You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.
通过定义初始化器来实现这个初始化过程,初始化器类似于可以调用的特殊方法来创建特定类型的新实例。与Objective-C初始化器不同,Swift初始化器不返回值。它们的主要作用是确保在首次使用类型的新实例之前正确初始化它们。

Instances of class types can also implement a deinitializer , which performs any custom cleanup just before an instance of that class is deallocated. For more information about deinitializers, see Deinitialization .
类类型的实例还可以实现deinitializer,它在释放该类的实例之前执行任何自定义清理。有关还原程序的更多信息,请参见还原。

为存储的属性设置初始值

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.
在创建类或结构的实例之前,类和结构必须将其存储的所有属性设置为适当的初始值。存储的属性不能保持不确定状态。

You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections.
您可以在初始化器中为存储的属性设置初始值,或者通过将默认属性值指定为属性定义的一部分来设置。下面几节将描述这些操作。

Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword:

调用初始化器来创建特定类型的新实例。最简单的形式是,初始化器就像一个没有参数的实例方法,使用init关键字编写:

The example below defines a new structure called Fahrenheit to store temperatures expressed in the Fahrenheit scale. The Fahrenheit structure has one stored property, temperature, which is of type Double:
下面的示例定义了一个名为华氏温度的新结构来存储以华氏温标表示的温度。华氏结构有一个存储属性,温度,类型为Double:

The structure defines a single initializer, init, with no parameters, which initializes the stored temperature with a value of 32.0 (the freezing point of water in degrees Fahrenheit).
该结构定义了一个没有参数的初始化器init,初始化存储的温度值为32.0(以华氏度为单位的水的冰点)。

默认的属性值

You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.
您可以在初始化器中设置存储属性的初始值,如上所示。或者,指定默认属性值作为属性声明的一部分。通过在属性定义时为其分配初始值来指定默认属性值。

You can write the Fahrenheit structure from above in a simpler form by providing a default value for its temperature property at the point that the property is declared:
您可以从上面以一种更简单的形式编写华氏温度结构,方法是在声明该属性时为其温度属性提供一个默认值:

自定义初始化

You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization, as described in the following sections.
您可以使用输入参数和可选的属性类型来定制初始化过程,或者通过在初始化期间分配常量属性来定制初始化过程,如下面的部分所述。

初始化参数
You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.
可以将初始化参数作为初始化器定义的一部分提供,以定义自定义初始化过程的值的类型和名称。初始化参数具有与函数和方法参数相同的功能和语法。

The following example defines a structure called Celsius, which stores temperatures expressed in degrees Celsius. The Celsius structure implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:), which initialize a new instance of the structure with a value from a different temperature scale:
下面的示例定义了一个名为摄氏度的结构,它存储以摄氏度表示的温度。摄氏度结构实现了两个自定义初始化器,分别名为init(fromFahrenheit:)和init(fromKelvin:),它们使用不同温度级别的值初始化结构的新实例:

The first initializer has a single initialization parameter with an argument label of fromFahrenheit and a parameter name of fahrenheit. The second initializer has a single initialization parameter with an argument label of fromKelvin and a parameter name of kelvin. Both initializers convert their single argument into the corresponding Celsius value and store this value in a property called temperatureInCelsius.

第一个初始化器有一个初始化参数,参数标签为fromFahrenheit,参数名称为fahrenheit。第二个初始化器有一个初始化参数,参数标签为fromKelvin,参数名为kelvin。两个初始化器都将它们的单个参数转换为相应的摄氏度值,并将该值存储在一个名为temperatureInCelsius的属性中。

参数名称和参数标签

As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer.

与函数和方法参数一样,初始化参数可以有用于初始化器主体内的参数名称,也可以有用于调用初始化器时的参数标签。

However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic argument label for every parameter in an initializer if you don’t provide one.
但是,初始化器的圆括号前不像函数和方法那样有标识函数名。因此,初始化器参数的名称和类型在确定应该调用哪个初始化器时起着特别重要的作用。因此,如果不提供初始化器中的每个参数,Swift将为它们提供一个自动参数标签。

The following example defines a structure called Color, with three constant properties called red, green, and blue. These properties store a value between 0.0 and 1.0 to indicate the amount of red, green, and blue in the color.
下面的示例定义了一个名为Color的结构,该结构具有三个常量属性,即红色、绿色和蓝色。这些属性存储在0.0到1.0之间的值,以指示颜色中红色、绿色和蓝色的数量。

Color provides an initializer with three appropriately named parameters of type Double for its red, green, and blue components. Color also provides a second initializer with a single white parameter, which is used to provide the same value for all three color components.
Color为其红色、绿色和蓝色组件提供了一个具有三个适当命名的参数Double类型的初始化器。Color还提供了带有一个白色参数的第二个初始化器,该参数用于为所有三个颜色组件提供相同的值。

Both initializers can be used to create a new Color instance, by providing named values for each initializer parameter:
两个初始化器都可以用来创建一个新的颜色实例,方法是为每个初始化器参数提供命名值:

Note that it is not possible to call these initializers without using argument labels. Argument labels must always be used in an initializer if they are defined, and omitting them is a compile-time error:
注意,不使用参数标签是不可能调用这些初始化器的。如果定义了参数标签,则必须始终在初始化器中使用它们,省略它们是编译时错误:

没有参数标签的初始化器参数
If you do not want to use an argument label for an initializer parameter, write an underscore ( _ ) instead of an explicit argument label for that parameter to override the default behavior.
如果您不想为初始化器参数使用参数标签,请为该参数编写下划线(_),而不是显式的参数标签,以覆盖默认行为。

Here’s an expanded version of the Celsius example from Initialization Parameters above, with an additional initializer to create a new Celsius instance from a Double value that is already in the Celsius scale:

下面是上面的初始化参数的摄氏度示例的扩展版本,其中有一个附加的初始化器,用于从摄氏度级别中的一个双值创建一个新的摄氏度实例:

The initializer call Celsius(37.0) is clear in its intent without the need for an argument label. It is therefore appropriate to write this initializer as init(_ celsius: Double) so that it can be called by providing an unnamed Double value.

初始化器调用摄氏度(37.0)的意图很清楚,不需要参数标签。因此,将这个初始化器编写为init(_ celsius:Double)是合适的,这样就可以通过提供一个未命名的Double值来调用它。

Swift-构造过程(Initialization)

前言

对于一个高中毕业后就除了毕业论文就再没认真写过东西的人来说,想坚持写点东西真的不太容易。最大的“阻碍”莫过于现在网上有各种各样大神花式分享的几乎从入门到精通的所有内容,当我们去拜读那些文章的时候,会从心底赞美这些人的无私和对专业知识的精通,同时难免体会到自己的无力,尤其是看看自己准备写,或者要写的东西的时候,就会彻彻底底的体会到两个字:low逼。虽然有时候想想别人的毕竟是别人的,自己学到的才是自己的,但是偶尔还是会受到一些刺激。昨天看到简书的一个哥们写的 浅谈iOS架构,下面有个人的评论虽然中肯,但是那种高高在上的感觉实在让人不爽。因为自己打算写一个大点的Swift语言开发的Demo,所以试图看看有没有什么好的项目架构建议,毕竟好习惯是慢慢培养的,以前开发的时候大都是随意的百度些如何创建iOS项目结构或者参考已有的项目去创建一些固定的文件夹,添加对应的文件。待的一直是创业公司,并没有什么架构师,所以开发过的项目总体看起来都很乱。一个好的项目架构往往会让我们的项目代码看起来赏心悦目。昨天还真的收获到一篇非常非常不错的系列文章:iOS架构谈,其实现在我还没看完,不过作者是真大神。

成长总会经历咿呀学步的阶段,知识的学习也是一样,尤其是作为普通的不能在普通的普通人,没有天赋,没有特长,甚至连坚持的毅力也乏乏,但是,又怎么能放弃呢?

今天也不知道哪来的这么多感慨,也许知道只是懒得去向为啥会有这感慨。开始正文,Swift的构造过程,这个应该是 The Swift Programming Language 中文版 这本教材中最长的一个章节了,不过我提前看了一遍,也并没有特别难的知识点,先来个小提纲:

  • 存储属性的初始赋值
  • 自定义构造过程
  • 默认构造器
  • 值类型的构造器代理
  • 类的继承和构造过程
  • 可失败构造器
  • 必要构造器
  • 通过闭包和函数来设置属性的默认值

构造过程是使用类、结构体或枚举类型的一个实例的准备过程。在新实例可用前必须执行这个过程。通过定义构造器(Initializers)来实现构造过程。与Objective-C中的构造器不同的是Swift构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。累的实例也可以通过定义析构器(deinitializers)在实例释放之前执行特定的清除工作。下一小节将会讲析构过程。

分条详述

  1. 存储属性的初始赋值

    类和结构体在创建实例时,必须为所有存储熟悉你设置合适的初始值。存储类型的值不能处于一种未知的状态。有两种赋值方式,一种是默认赋值,一种是在默认构造器中赋值。需要注意的是当为存储属性设置默认值或者在构造器中为其赋值时,它们的值是被直接赋值的,不会触发属性观察者(willSetdidSetsetter):

    //  在构造器中赋值
    struct Scrore 
    var level: String
    init() 
        level = "SS"
    
    
    var score = Scrore()   //  此时执行构造过程,为level赋值
    score.level        //  "SS"
    score.level = "C"     //  重新赋值
    //  默认属性值
    struct Car 
    var wheels = 4
    
    var car = Car()
    car.wheels   //  4

    当一个属性总是使用相同的属性值,建议使用默认属性值,会使代码更加简洁易读。

  2. 自定义构造过程

    可以通过输入参数和可选属性来自定义构造过程,也可以在构造过程中修改常量属性。

    • 构造参数

      举个例子,输入一个绝对温度或者华氏温度,将其转化为摄氏度,举这个例子一方面是教材就这个例子,另外,小小Demo我竟然有三个单词不认识,不能忍:

      //  单词学习:Celsius: 摄氏度    temperature: 温度   fahrenheit:华氏温度
      struct Celsius 
      var temperatureInCelsius: Double
      //  构造器一:fromFahrenheit 是参数外部名, fahrenheit 是参数内部名
      init(fromFahrenheit fahrenheit: Double) 
          temperatureInCelsius = (fahrenheit - 32) / 1.8
      
      //  构造器二:下划线 _ 表示忽略参数外部名,前面有介绍,kelvin 是参数内部名
      init(_ kelvin: Double) 
          temperatureInCelsius = kelvin - 273.15
      
      //  构造器三: 
      init(mutiableNumber: Double) 
          temperatureInCelsius = mutiableNumber * 2
      
      
      //  实例测试
      //  构造器一,只显示外部参数名
      var originCelsius = Celsius(fromFahrenheit: 300)
      originCelsius.temperatureInCelsius    //  148.8888888888889
      //  构造器二,调用时不显示外部参数名,因为被忽略了
      originCelsius = Celsius(300)
      originCelsius.temperatureInCelsius    //  26.85000000000002
      //  构造器三,默认只有一个参数名,既是参数外部名,又是参数内部名
      originCelsius = Celsius(mutiableNumber: 300)
      originCelsius.temperatureInCelsius    //   600
    • 参数的内部名称和外部名称

      参照上面的代码构造器一、二、三,显然,参数名在构造器中非常重要,因为构造器都是 init(),参数名则是对构造器的注释。如果在定义构造器时没有提供参数的外部名,Swift会为每个构造器的参数生成一个跟内部名字相同的外部名,如上面代码中的构造器三,这就相当于在每个构造参数之前加了个哈希符号。使用下划线表示忽略构造函数的外部名,实例的时候也不会显示,如构造器二。

    • 可选属性类型

      当类或结构体中包含一个逻辑上允许取值为空的存储属性时,必须要将其设置为可选类型optional type。可选类型的属性将其自动初始化为空 nil,表示这个属性实故意在初始化时设置为空的。否则必须在初始化时为其赋值。比如一个问题,必须先问,才能有回答,所以回答的属性在类型实例化的时候可以为空,再次提醒一下,如果存储属性不是可选类型,那么类型初始化结束时必须给该属性赋值,否则会编译错误:

      //  允许为空的属性必须是可选类型
      struct AskAndAnswer 
      var question: String
      var answer: String?
      init(putYourQurestion question: String) 
          self.question = question
      
      func ask() 
          //  执行提出问题的方法
          print(question)
      
      
      var test = AskAndAnswer(putYourQurestion: "How old are you?")
      test.ask()
      test.answer = "ni cai"

    在构造过程中,常量既可以默认赋值,也可以在构造方法中赋值。一旦常量属性被设置,它将永远不能修改。对于类的实例来说,它的常量属性只能在定义它的类中赋默认值或者构造过程中赋值,不能在子类中修改。

  3. 默认构造器

    如果类或者结构体的所有属性都有默认值,同事没有自定义的构造器,那么Swift会为这些结构体或类提供默认的、隐藏构造器。

    类的默认构造器是唯一的,但是结构体可以有逐一的成员构造器,即实例化时为每一个属性赋值,下面实例代码中对两种方式都做了说明:

    //  类,属性已经全部有默认值,实例化时只有下面这种方式
    class GoodsInfo 
    var weight: Double?   //  可选类型,默认值为nil
    let price = 10
    var name = "meat"
    
    let singleGoods = GoodsInfo()     //  默认构造器
    //  结构体,属性都有值,实例时有两种方式
    struct Size 
    var height = 0.0
    var width = 0.0
    var length: Double? 
    
    var singleSize = Size()    //  默认构造器
    var nextSiz = Size(height: 20, width: 40, length: 50)     //  逐一成员构造器
    //  结构体,属性部分或者全部都没值,只有之中实例化方式
    struct RectSize 
    var height = 0.0
    var width = 0.0
    var length: Double
    
    var rect = RectSize(height: 11, width: 11, length: 11)   //  如果所有存储属性没有提供默认值,就只有这种实例方式
  4. 值类型的构造器代理

    构造器可以通过调用其他构造器来完成实例的部分构造过程,这一过程称为构造器代理,它能减少多个构造器之间的代码重复。

    构造器代理的实现规则和形式在值类型(枚举enumeration、结构体structure)和类类型(类class)中有所不同。因为值类型没有继承的功能,所以构造器代理只为自身提供,过程相对简单。类则不同,它可以继承自其他类,这意味着类有责任保证其所有继承的存储属性在构造时也能正确的初始化,下一个小知识点将会讲到 类的继承和构造过程 这个知识点。

    对于值类型,可以使用self.init在自定义的构造器中引用这个值类型的其他构造器。并且只能在构造器内部调用self.init,并且调用的时候并没有代码补全提示,所以要手动输入。

    如果为一个值类型定义了一个定制的构造器,那么将不能使用默认的构造器。说简单点,如果值类型中出现init这个方法,那么值类型实例化时就必须要用带有init方法中的一个。加入既想定制构造器,又想使用默认的构造器,那么就用 扩展(extension 吧。这个知识点还在后面,重要程度,嗯,五颗星吧。下面的实例代码很好的解释了值类型的构造器代理和自定义构造器,注意看注释:

    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()   // 矩形宽高
    //  构造器一:这个和默认构造器的功能是一样的,但是,注意!这个不是默认构造器,这个不是默认构造器!!不信你把这行代码注释掉,然后 var singleRect = Rect() 这么实例化试试?
    init()
    //  构造器二:功能上和结果体的逐一成员构造器一样
    init(rectOrigin origin: Point,rectSize size: Size) 
        self.origin = origin
        self.size = size
    
    //  构造器三:秀一下如何使用构造器代理
    init(rectCenter center: Point, rectSize size: Size) 
        let originX = center.x - size.width / 2
        let originY = center.y + size.height / 2
        //  使用构造器代理,这里代码没有补全提示
        self.init(rectOrigin: Point(x: originX, y: originY), rectSize: size)
    
    
    //  实例化
    var singleRect1 = Rect()
    var singleRect2 = Rect(rectCenter: Point(x: 3, y: 4), rectSize: Size(width: 30, height: 30))
    var singleRect3 = Rect(rectOrigin: Point(x: 12, y: 15), rectSize: Size(width: 24, height: 36))
  5. 类的继承和构造过程

    • 指定构造器和便利构造器

      类里面所有的存储属性,包括所有继承自父类的属性,都必须在构造过程中设置初始值。Swift提供两种类型的构造器来确保所有的类实例中存储属性都获得初始值,它们分别是指定构造器和便利构造器。上文中说到的类的默认构造器,所有的存储属性在构造完成前必须全部都有初始值。

      指定构造器是类中最主要的构造器,每个类中都必须拥有至少一个指定构造器,其实默认的的构造器也属于指定构造器。在某些情况下,许多类通过继承了父类中的指定构造器而满足了这个条件。

      便利构造器是类中比较次要的、辅助性的构造器。应当只在必要的情况下使用便利构造器,比方说某种情况下通过使用便利构造器来快捷调用某个指定构造器,能够节省更多开发时间并让类的构造过程更清晰明了。

      类的指定构造器写法跟值类型的简单构造器一样,便利构造器也采用相同的写法,但需要在init关键字之前放置convenience关键字:

      //  指定构造器
      init(parameters) 
      statements
      
      //  便利构造器
      convenience init(parameters) 
      statements
      
    • 类的构造器代理规则

      为了简化指定构造器和便利构造器之间的调用关系,Swift采用以下三条规则来限制构造器之间的代理调用:

      • 规则1:指定构造器必须调用其父类的指定构造器(如果存在调用行为);
      • 规则2:便利构造器必须调用同一类中定义的其他构造器(只要使用便利构造器);
      • 规则3:便利构造器必须最终以调用一个指定构造器结束。即必须有super.init(...)方法。

      简而言之,就是指定构造器必须总是向上代理,便利构造器必须总是横向代理。下面图例中展示了一种针对四个类的类层级结构,它演示了指定构造器如何在类层级中充当管道的作用,在类的构造器链上简化了类之间的相互关系,也表达出了便利构造器智能横向代理的意思:

    • 两段式构造过程

      P.S.先提前说吧,我并不确定类的构造过程是不是真的需要这么细,至少现在这个小节我已经很认真的读两遍了,原谅我还不是很能理解两段式的构造过程到底是怎样的具体过程。希望在以后的开发中能对这小节的内容有深刻的体会。

      Swift中类的构造过程包含两个阶段。第一个阶段,每个存储型的属性通过引入它们的类的构造器来设置初始值。每当一个存储属性的初始值被确定后,第二阶段开始,他给每个类一次机会在新实例准备使用之前进一步定制它们的存储型属性。

      两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问;也可以防止属性被另外的构造器意外的赋予了不同的值。(P.S.教材中对于两段式讲了非常多的内容,唯一的缺憾就是没有代码示例,而我也并没有理解太好,本来想按照自己现有的理解写一段,但是总感觉不对,所以就先空着吧,理解了再回来补)

      Swift编译器将执行4中有效的安全检查,以确保两段式构造过程能顺利完成:

      • 安全检查1:指定构造器必须保证它所在的类引入的所有属性都必须先初始化完成,之后才能将其它的构造任务向上代理给父类中的构造器。
      • 安全检查2:指定构造器必须先向上代理调用父类的构造器,然后再为继承的属性设置新值。如果没有这么做,指定构造器赋予的新值将被父类中的构造器覆盖。
      • 安全检查3:便利构造器必须先代理调用同一类中的其他构造器,然后再为任意的属性赋新值。如果没这么做,便利构造器赋予的新值将会被同一类中的其他指定构造器所覆盖。
      • 安全检查4:构造器在第一阶段完成之前,不能调用任何实例方法、不能读取任何实例属性的值,self的值也不能被引用。

      类实例在第一阶段结束以前并不是完全有效,仅能访问属性和调用方法,一旦完成第一阶段,该实例才会声明为有效实例。以下是两段式构造过程中基于上面安全检查的构造流程展示。

      首先是阶段1:

      • 某个指定构造器或便利构造器被调用;
      • 完成新实例内存的分配,但此时内存还没有被初始化;
      • 指定构造器确保其所在的类引入的所有存储性属性都已经赋初值。存储类型所属的内存完成初始化;
      • 指定构造器将调用父类的构造器,完成父类属性的初始化;
      • 这个调用父类构造器的过程沿着构造器链一直往上执行,直到到达构造器链的最顶部;
      • 当到达构造器链最顶部,且已确保所有的实例包含的存储型属性都已经赋值,这个实例的内存被认为已经完全初始化,此时阶段1完成。

      阶段2:

      • 从顶部构造链一直往下,每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问self、修改它的属性并调用实例方法等等。
      • 最终,任意构造器链中的便利构造器可以有机会定制实例和使用self

      看明白了么?教材中图解了这两个阶段。下图是构造过程阶段1,一旦父类中所有的属性都有了初始值,实例的内存被认为是完全初始化,而阶段1已完成。

      阶段1完成后,父类中的指定构造器现在有机会进一步来定制实例(尽管它没有这必要)。一旦父类中指定的构造器完成调用,子类的定制构造器可以执行更多的定制操作(同样,它也没有这种必要)。最终,一旦子类的指定构造器完成调用,最开始被调用的便利构造器可以执行更多的定制操作。

    • 构造器的继承与重写

      跟 Objective-C 的子类不同,Swift中的子类不会默认继承父类的构造器。Swift这种机制可以防止一个父类的简单构造器被一个更专业的子类继承时,却错误的用父类来创建子类的实例。

      当重写父类的指定构造器、属性、方法或者下标脚本等特性时,都要在前面加上关键字override,只要含有override修饰符就回去检查父类是否有相匹配的重写指定构造器和验证重写构造器参数。

      下面的例子中定义了一个基础类叫Vehicle,基础类中声明一个存储属性numberOfWheels、计算属性descroption

      class Vehicle 
      var numberOfWheels = 0     //  存储属性
      var description: String      //  计算属性
          return "number of wheels = \\(numberOfWheels)"
      
      
      //  默认构造器创建实例
      let vehicle = Vehicle()

      Vehicle类并没有自定义构造器,前面说过,它会生成一个默认构造器,而默认构造器在类中是指定构造器。

      创建一个继承Vehicle的子类Bicycle,这里用到了继承:

      class Bicycle: Vehicle 
      override init()       //  重写
          super.init()    
          numberOfWheels = 2
      
      

      Bicycle的构造器init()一开始调用super.init()方法,这个方法的作用是调用Bicycle的父类Vehicle。这样可以确保Bicycle在修改属性前它所继承的属性numberOfWheels能被Vehicle类初始化。子类可以在初始化时修改继承到的变量属性,但是不能修改继承过来的常量属性。

    • 自动构造器的继承

      子类不会默认继承父类的构造器,但是如果满足下面规则,父类构造器是可以被自动继承的:

      • 规则1:如果子类没有任何指定构造器,它将自动继承父类的指定构造器。

      • 规则2:如果子类提供了所有父类指定构造器的实现 – 不论是通过规则1继承来的,还是通过自定义实现的 – 它将自动继承所有父类的便利构造器。

      即使在子类中添加了更多的便利构造器,这两条规则仍然适用。看下面的实例代码,注意注释文字:

      class Vehicle 
      var numberOfWheels = 0     //  存储属性
      var isFly = false        //  是否可以飞
      var description: String      //  计算属性
          return "number of wheels = \\(numberOfWheels)"
      
      //  指定的构造器1
      init(vehicleIsFly isFly: Bool) 
          self.isFly = isFly
          print("\\(isFly ? "The vehicle can fly" : "can not fly")")
      
      //  指定构造器2
      init(vehicleCount count: Int, vehicleWheels wheels: Int) 
          self.numberOfWheels = wheels
          print("totleWheels = \\(count * wheels)")
      
      //  便利构造器
      convenience init(vehicleIsSpeed speed: Double)  
          self.init(vehicleIsFly: true)
          self.isFly = true
      
      
      //  创建子类1
      class Bicycle: Vehicle 
      //  满足规则1,子类中没有定义任何指定构造器,定义便利构造器不影响规则1
      convenience init(BicyclePrice price: Double) 
           self.init(vehicleIsFly: true)
           print("price = \\(price)")
      
      /*********** 如果加上下面这三行代码,重写部分指定方法,会有各种错误 ***********/
      /*
      override init(vehicleCount count: Int, vehicleWheels wheels: Int) 
          super.init(vehicleCount: count, vehicleWheels: wheels)
          print("subclass override")
      
       */
      
      //  子类1的实例
      let bicycle1 = Bicycle(vehicleCount: 3, vehicleWheels: 2)   //  继承到的指定构造器1
      let bicycle2 = Bicycle(vehicleIsFly: true)           //  继承到的指定构造器2
      let bicycle3 = Bicycle(vehicleIsSpeed: 100)          //  继承到的便利构造器
      //  自身的便利构造器
      let bicycle4 = Bicycle(BicyclePrice: 1000)
    • 指定构造器和便利构造器实例

      其实,上面的实例代码就是一个比较完整的实例了。

  6. 可失败的构造器

  7. 必要构造器

  8. 通过闭包和函数来设置属性的默认值

结束语

这一节看的还真是痛苦啊,断断续续写了5天还没有写完,写的还真是啰嗦,加上自己始终不明不白,这感觉真不咋地。就这么着吧,打个点,以后积累了一定了知识后再回来补,如果还能记得的话……

以上是关于Initialization构造函数(一)的主要内容,如果未能解决你的问题,请参考以下文章

RAII(Resource Acquisition Is Initialization)简介

Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )

Kotlin类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )

react 组件生命周期

python 构造函数__init__() 和 实例属性实例方法

Swift-构造过程(Initialization)