构造过程

为了生成类、结构体、枚举等的实例,而做的准备过程,叫做构造过程。 为了这个过程,我们一般会定义一个方法来完毕,这种方法叫做构造器。当然它的逆过程,叫做析构器,用于在实例被释放前做一些清理工作以及一此自己定义化的处理。


为存储型属性设置初始值
类和结构体在生成实例那一刻,必须为全部的属性赋以特定的初始值。

要么在定义存储型属性的时候直接给个初始值,否则就必须在构造器里面指定一个初始值。
上面说的这两种情况,都不会触发存储型属性的监听者行为(property observer)。

struct MyClass {
     var number: Int
     init () {          //这个就是构造器,它没有返回值
          number = 1     //为存储型属性指定一个初始值
     }
}

或者
struct MyClass {
     var number: Int = 1   //直接在存储型属性定义的时候。指定一个初始值

还能够自己定义构造器,为它传入參数。然后对属性做对应的初始化:
struct MyClass {
     var number: Int
     init (num: Int) {          //这个就是构造器,它没有返回值
          number = num     //为存储型属性指定一个初始值
     }

     init (num: Int, byTimes: Int) {     //能够定义多个构造器
          number = num * byTimes
     }
}

let myInstance1 = MyClass(num:1)          //使用第一种构造器生成一个实例
let myInstance2 = MyClass(num:10, byTimes:3)     //使用另外一种构造器生成还有一个实例
注意:这里与之前的类方法稍有不同,swift会为每一个參数都提供一个外部使用名,而这个行为在类方法中。是从第二个參数開始才有的(笔记十一中有提到)。当然你能够指定一个外部使用名,来替代swift的默认行为(“_”依旧能够禁止swift提供外部使用名)。

可选类型属性
假设我们在定义可选类型属性的时候没有赋值。而且,在构造器中也没有赋值的话,swift为我们将这个属性的值设置为nil。

常量属性
在构造过程结束之前。常量属性的值是能够任意改动的(当然要用相同类型的值)。
注意:子类是不能够改动父类的常量属性的。

默认构造器
swift会为那些没有构造器,而且全部属性都有初值的类,提供一个默认构造器(编译器做的事。在swift代码中看不见),上面已经出现过这种一个类了:
struct MyClass {
     var number: Int = 1
}

这个类中,我们并没有指定一个构造器,而且number属性也有初始值。那么swift就会提供一个默认的构造器,使得number属性确实等于1......(对于新手来说,这可能非常难理解,就先这么记吧,由于这块涉及到内存分配的问题,暂且不展开记录。后继等把手冊全都看完,我还想写个对swift中的各种类型变量做个内存模型的分析的系列笔记。到时候再来说这个问题。

)


结构体的属性列表构造器(Memberwise Initializers for Structure Types)
在结构体中,除了上面说过的默认构造器外,swift会提自己主动接受一个”全部用于存储的属性带有初始值的列表“的构造器,前提是我们没有为struct写自己定义构造器。


struct MyStruct {
     var name = “1”
     var number = 2
}

let myStructInstance = MyStruct(name: “Hello”, number:100)
这相当于提供了一个 init(name:String, number:Int) 的构造器,但这个行为是swift帮我们做的。

值类型的构造器代理
构造器还能调用其他的构造器作为构造过程的一部分。这个过程,叫做构造器代理。

值类型(结构体,枚举)并不支持继承,所以,他们的构造器代理与类的构造器代理的规则和形式有所差别。
值类型的构造器相对简单,由于类会继承非常多父类的存储型属性,类就有责任在构造过程中保证它继承来的属性被正确的初始化(这个等会再说)。


先来看一个官方的样例:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJnZXJt/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">




这个样例中,有三个构造器,第一个是个空的{}。当这个构造器被调用的时候:
let myRect = Rect()
origin会是 (0.0, 0.0), size会是 (0.0, 0.0),所有都是初始值。


第三个构造器中(第12行)调用了第二个构造器,这样的方法,能够降低第三个构造器的代码。假设没有这样的方式的话,那么在这个位置,我们就要把第二个构造器的内容复制一份,放在这里(这显然是不好的)。

类继承和构造过程
switf为类提供了两种构造器,以确保全部的属性都能被值始化:指定构造器 和 便利构造器

//吐槽:原本为了方便交流而定义了各种各样的名字,结果在上手学习的时候。却造成了极大的障碍。不知道这算不算是得不尝失。

但既然已经有人给各种各样的调用方式都起了名字,而且又出如今官方文档里。那就逆来顺受吧,仅仅要我们知道,事实上这玩意就是那么回事。。。

即可了


这里的指定构造器和便利构造器在官方文档上说了一大堆的解释,各种名字概念天花乱坠。说得头都晕了。无非就是为了方便使用而封装了一层调用而已啊,绕晕有什么意思,还是临时先放一下吧,一会儿再说。

构造器调用链
为了简化指定构造器和便利构造器的调用关系,swift指定了三条规则:
1. 构造器代理必须调用它的直接父类的指定构造器
2. 便利构造器必须调用它同一个类中定义的其他构造器
3. 便利构造器的结尾部分必须调用一个指定构造器

一个方便的记忆方法是(这是文档上的):
指定构造器必须总是向上代理
便利构造器必须总是横向代理

//吐槽:说得好听点是为了简化而搞出来的一堆并不简单的规则。说难听点不就是为了商业目的,减少门槛而搞出来的所谓自己主动推导而引出来的一系列的恶心问题嘛。

。。。


向上代理的意思就是调用父类的指定构造器
横向代理的意思就是调用它自己类内的构造器
官方的图解:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJnZXJt/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


每个大的蓝色广块表示的是一个类。每个小的蓝色广块(写着 Designated)代表指定构造器,每个土黄色的方块(写着 Convenience)代表便利构造器。 这个图就是对上面三条规则的解释。

两段式的构造过程(Two-Phase Initialization)
swift中类,包括两个阶段。
第一阶段,每一个存储型属性通过它们自己的类构造器来设置初始值。
第二阶段。每个存储型属性都能够进一步的设置他们定制化的初始化。

我拿一小段代码来说明这个文档的SB之处(这段代码明显是错的):
int myNumA = 1

func myFunc() {
     myNumA = myNumB          //在这里的时候 myNumB还没定义,也没初始化,明显是错的
}

int myNumB = 2          //myNumB定义+初始化

所谓的两段式构造过程,就是告诉我们。在使用myNumB之前。要确保它被定义而且被初始化了。

。。。。

于是。假设按着两段式构造过程,我们上面的代码正确写法应该是:


int myNumA = 1
int myNumB = 2

func myFunc() {
     myNumA = myNumB
}
//看起来是不是非常好笑。

。。

。用了一大堆的描写叙述,就是想说明这种问题。


构造器的继承和重写
swift中,子类不会默认的继承父类的构造器。可是我们偶尔会认为父类的构造器的功能不够强大,这个时候就须要在子类中,重写构造器,以达到特定的目的。

假设重写的是一个指定构造器,写完我们的逻辑之后,记得要调用父类的那个构造器。
假设重写的是一个便例构造器,必需要调用这个类中的其他指定构造器。


构造器的重写,与属性、方法以及下标的重写不同。我们不须要在前面写 overridekeyword。


自己主动构造器的继承
在之前的笔记中以及文档中,一直在说。swift不会默认的继承父类的构造器,但实际上,非常多样例已经说明能够自己主动继承了(为了避免误解与暴乱,扔白菜之类的事情发生,我一直都没说。。。:))

swift的构造器继承机制,要满足下面两点:
1. 假设子类未定义不论什么指定构造器,它将会自己主动继承全部父类的指定构造器。
2. 假设子类中定义了全部父类的指定构造器的实现(通过规则1 或是 自己实现),它将会自己主动继承全部父类的例利构造器。

指定构造器及便利构造器的语法
指定构造器:
init (參数) {
     函数体
}

便利构造器:
convenience init(參数) {          //这里有个conveniencekeyword
     函数体
}

仅仅要知道convenience型的构造器,仅仅能调用它自己这个类中的非convenience构造器即可了。


用闭包或者函数设置属性的默认值
class MyClass {
     var myNumbers:Int[] = {
          var tmpNum = Int[]()     //生成一个暂时数组。用来在闭包最后给myNumbers赋值
          for i in 1…10 {
               tmpNum.append(i)     //加入元素
          }
          return tmpNum     //闭包的返回值
     }()          //这个()一定不能够省,不然的话,myNumbers就成了闭包这个函数,而不是闭包的返回值了

     func getNumbers() -> Int[] {
          return myNumbers
     }
}

let myInstance = MyClass()
myInstance.getNumbers()      //这条取到了MyClass的myNumbers数组

swift 笔记 (十四) —— 构造过程的更多相关文章

  1. 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9712321 作者:七十一雾央 新浪微博:http:/ ...

  2. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  3. (C/C++学习笔记) 十四. 动态分配

    十四. 动态分配 ● C语言实现动态数组 C语言实现动态数组,克服静态数组大小固定的缺陷 C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量.一旦定义了一个数组,系统将为它分配一个 ...

  4. (C/C++学习笔记) 十五. 构造数据类型

    十五. 构造数据类型 ● 构造数据类型概念 Structured data types 构造数据类型 结构体(structure), 联合体/共用体 (union), 枚举类型(enumeration ...

  5. Swift学习笔记十四:构造(Initialization)

         类和结构体在实例创建时,必须为全部存储型属性设置合适的初始值. 存储型属性的值不能处于一个未知的状态.     你能够在构造器中为存储型属性赋初值,也能够在定义属性时为其设置默认值.下面章节 ...

  6. Swift学习笔记十四

    Deinitialization 当类的实例对象即将要被释放时,会立即调用deinitializer,通过deinit关键字来定义deinitializer,和initializer一样,它也只存在于 ...

  7. python3笔记十四:python可变与不可变数据类型+深浅拷贝

    一:学习内容 python3中六种数据类型 python赋值 python浅拷贝 python深拷贝 二:python3六种数据类型 1.六种数据类型 Number(数字) string(字符串) L ...

  8. TCP/IP详解 笔记十四

    TCP/IP协议(二)  连接的建立与终止 tcpdump -S输出TCP报文的格式 格式: 源>目的:标志 (标志就是tcp头部).标识首字符意义如下: 例如:telnet 某服务的输出(包括 ...

  9. swift 笔记 (十八) —— 扩展

    扩展 扩展能够让我们给一个已有的类.结构体.枚举等类型加入�新功能,包含属性和方法,甚至是构造器,下标,支持协议等等... 甚至是我们拿不到源码的类.结构体.枚举,我们依旧能够给它加扩展... 看到这 ...

随机推荐

  1. 最短路( spfa)

    最短路 http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2622 #include <std ...

  2. Appium - xpath

    基本属性定位 以淘宝app为例,定位左上角扫一扫按钮 1.可以通过text文本定位到 //*[@text='text文本属性'] # 定位text driver.find_element_by_xpa ...

  3. 《疯狂Python讲义》重要笔记——Python简介

    简介 Python是一种面向对象.解释型.弱类型的脚本语言,同时也是一种功能强大的通过语言,它提供了高效的高级数据结构,还有简单有效的面向对象编程. 在大数据.人工智能(AI)领域应用广泛,因此变得流 ...

  4. 【python】random

    1.random 和其他语言一样,返回大于等于0.小于1的浮点数 2.uniform(a,b) 返回大于等于a.小于等于b的浮点数 3.randint(a,b) 这个很好理解,返回一个介于a和b之间的 ...

  5. IIS日志分析:SC-Status语义

    在网站属性-网站-日志(属性) 中进行设定该站点IIS日志常规属性和扩展属性,扩展属性设置IIS日志包含字段显示. HTTP协议状态(sc-status)码的含义  IIS中 100 Continue ...

  6. dubbo之负载均衡

    在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用. Random LoadBalance 随机,按权重设置随机概率. 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按 ...

  7. C#异步Async、Task、Await

    参考http://www.cnblogs.com/jesse2013/p/async-and-await.html 事例: static void Main(string[] args) { ; i ...

  8. python 处理中文 读取数据库输出全是问号

    ref:http://www.cnblogs.com/zhoujie/archive/2013/06/07/problem1.html 1.python连接mssql数据库编码问题 python一直对 ...

  9. 利用Xpath和jQuery进行元素定位示例

    利用Selenium在做前端UI自动化的时候,在元素定位方面主要使用了XPATH和jQuery两种方法.XPATH作为主要定位手段,jQuery作为补充定位手段.因为在通过XPATH进行定位的时候,S ...

  10. 在vue中写一个跟着鼠标跑的div,div里面动态显示数据

    1.div应该放在body里面,这是我放在body中的一个div里面的div <!-- 信息查看层 --> <div class="floatDiv" :styl ...