// 构造过程 是使用类,结构体 或 枚举类型的实例之前的准备过程,

// 在新实例可用前必须执行这个过程, 具体操作包括 设置实例中每个存储型属性的初始值 和 执行其他必须的设置 或 初始化工作

// 通过定义 构造器 来实现构造过程, 这些构造器可以看做是用来创建特定类型新实例的 特殊方法, 与 OC 中的构造器不同, Swift 的构造器不需要返回值, 它们的主要任务是保证 新实例在第一次使用前完成正确的 初始化

// 类的实例也可以定义 析构器 在实例释放前执行 特定的清除工作

// 存储属性的初始赋值

// 类和结构体在穿件实例时, 必须为所有存储属性设置合适的初始值, 存储型属性的值不能处于 一个位置的状态

// 你可以在 构造器 中为存储型属性赋初值, 也可以在定义属性时 为其设置默认值

// 注意 : 当你为存储型属性设置默认值 或者 在构造器 中为其赋值时, 他们的值是被直接设置的, 不会触发任何属性观察者

// 构造器

// 构造器在创建某个 特定类型 的新实例时被调用, 他的最简形式类似于 一个不带任何参数的实例方法, 以关键字 init 命名

// init(){

//

// }

// 下面的例子中定义了一个用来保存华氏温度的结构体 Fahrenheit, 它拥有一个 Double 类型的存储属性 temperature :

struct Fahrenheit{

var temperature: Double

init() {

temperature = 32.0

}

}

var f = Fahrenheit()

print("The default temperature is \(f.temperature) Fahrenheit")

// 这个结构体定义了一个不带任何参数的 构造器 init ,并在里面将存储型属性 temperature 的值 初始化为 32.0

// 默认属性值

// 如前所述, 你可以在构造器中为存储型属性设置初始值, 同样, 你也可以在属性声明时为其设置默认值

// 注意 : 如果一个属性总是使用相同的初始值, 那么为其设置一个默认值, 那么为其设置一个默认值 比 每次都在构造器中赋值要好, 两种方法的效果是一样的,只不过 使用默认值 让属性的初始化 和 声明结合的更紧密. 使用默认值能让你的构造器更简洁, 更清晰, 且能通过 默认值自动推导出属性的类型, 同时, 它也能让你充分利用默认构造器, 构造器继承等特性 .

// 你可以使用更简洁的 方式在定义 结构体 Fahrenheit 时为属性 temperature 设置 默认值

struct Fahrenheit2{

var temperature = 32.0

}

// 自定义构造过程

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

// 构造参数

// 自定义 构造过程 时, 可以在定义中提供构造函数, 指定所需值的类型 和 名字, 构造函数的功能 和 语法跟函数的方法的参数相同

// 下面的例子中定义了一个包含 摄氏度温度的 结构体 Celsius, 它定义了两个不同的构造器: init(fromFahrenheit:) 和 init(formKelvinL), 二者分别通过不同温标下的温度值来创建新的实例:

struct Clesius{

var temperatureInCelsius: Double

init(fromFahrenheit fahrenHeit: Double) {

temperatureInCelsius = (fahrenHeit - 32.0) / 1.8

}

init(fromKelvin kelvin: Double) {

temperatureInCelsius = kelvin - 273.15

}

}

let boilingPointOfWater = Clesius.init(fromFahrenheit: 212.0)

print(boilingPointOfWater.temperatureInCelsius)

let freezingPointOfWater = Clesius.init(fromKelvin: 273.15)

print(freezingPointOfWater.temperatureInCelsius)

// 第一个构造器拥有一个构造函数, 其外部名字为 fromFahrenheit , 内部名字为 Fahrenheit, 第二个构造器也拥有一个构造函数, 其外部名字是 fromKelvin , 内部名字是 kelvin , 这两个构造器都是讲唯一的参数值转换成摄氏温度值, 并保存在属性 temperatureInCe

// 参数的内部名称 和 外部名称

// 跟函数和方法参数相同, 构造参数也拥有一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字

// 然而, 构造器并不像函数和方法那样在括号前有一个可辨别的名字, 因此在调用构造器时, 主要通过构造器中 参数名和类型 来确定应该被调用的构造器. 正因为参数如此重要, 如果你在定义构造器时 没有提供参数的外部名字, Swift 回味构造器自动生成一个跟内部名字相同的外部名

// 下面的例子中 定义了一个 Color 结构体, 它包含三个常量: red , green , blue, 这些属性可以存储 0.0 到 1.0 之间的值, 用来指示颜色中, 红, 绿, 蓝成分的含量

// Color 提供了一个构造器, 其中包含三个 Double 类型的参数, Color 也可以提供第二个构造器, 它只包含名为 white 的 Double 类型的参数, 它被用于给上述三个构造参数赋予同样的值

struct Color{

let red, green, blue: Double

init(red: Double, green: Double, blue: Double) {

self.red = red

self.green = green

self.blue = blue

}

init(white: Double) {

red = white

green = white

blue = white

}

}

// 两个构造器都能用于创建一个新的 Color 实例, 你需要为构造器每个外部参数传值

let magenta = Color.init(red: 1.0, green: 0.0, blue: 1.0)

let halfGray = Color.init(white: 0.5)

// 注意 : 如果不用过外部参数名字传值, 你是没有办法调用这个构造器的, 只要这个都早起定义了某个外部参数的参数名, 你就必须使用它. 忽略它导致编译错误

// 不带外部名的构造器参数

// 如果你不希望为构造器的某个参数提供外部名字, 你可以使用下划线 (_) 来显式描述他的外部名, 一次重写上面所说的默认行为

struct Celsius{

var temperayureInCelsius: Double

init(fromF f: Double) {

temperayureInCelsius = (f - 32.0) / 1.8

}

init(fromK k: Double) {

temperayureInCelsius = k - 273.15

}

init(_ celsius: Double) {

temperayureInCelsius = celsius

}

}

let bodyTemperature = Celsius.init(37.0)

// 调用 Celsius(37.0) 意图明确, 不需要外部参数名称, 因此适合使用 init(_ celsius: Double) 这样的构造器, 从而可以提供 Double 类型的参数值调用构造器, 而不需要加上外部名称

// 可选属性类型

// 如果你定制的类型包含一个 逻辑上允许取值为空的存储型属性 -- 无论是因为它无法再初始化时赋值, 还是 因为它在之后某个时间点可以赋值为空 -- 你都需要将它定义为可选类型, 可选类型的属性自动初始化 为 nil , 表示这个属性是有意在初始化时 设置为空的

// 下面的例子定义了一个 SurveyQuestion, 它包含一个可选字符串属性 response:

class SurveyQuestion{

var text: String

var response: String?

init(text: String) {

self.text = text

}

func ask() {

print(text)

}

}

let cheeseQuestion = SurveyQuestion.init(text: "Do you like cheese?")

cheeseQuestion.ask()

cheeseQuestion.response = "Yes. I do like cheese"

// 我们将 response 声明为 String? 或者说是 可选字符串类型, 当 SuveyQuestion 实例化时, 它将自动复制为 nil, 表明此字符串暂时还没有值

// 构造过程中常量属性的修改

// 你可以 在构造过程中的任意时间点 给常量属性指定一个值, 只要在构造过程结束时 是一个确定的值, 一旦常量属性被赋值, 它将永远不被改变

// 注意 : 对于类的实例来说, 它的 常量属性 只能在 它的类的构造过程中修改, 不能再子类中修改

// 你可以修改上面的 SurveyQuestion 实例, 用常量属性提到变量属性 text, 表示问题内容 text 在 SurveyQuestion 的实例被创建之后不会再被修改, 尽管 text 属性现在是常量, 我们任然可以 在类的构造器中设置它的值

class SueveyQuestions{

let text: String

var response: String?

init(text: String) {

self.text = text

}

func  ask() {

print(self.text)

}

}

// 在默认构造器中修改常量属性的值, 常量属性的值 不能已经设置默认值, 否则会报错

// 默认构造器

// 如果 结构体 或 类的所有属性 都有默认值, 同时没有自定义的构造器, 那么 Swift 会给这些 结构体 或 类提供一个 默认的构造器, 这个默认构造器将简单地创建  一个所有属性都设置默认值的实例

class ShoppingListItem{

var name: String?

var quantity = 1

var purchased = false

}

var item = ShoppingListItem()

// 由于 ShoppingListItem 类中的 所有的属性都有默认值, 且它是没有父类的基类, 他讲自动获得一个 可以为所有属性设置默认值的 默认构造器

// 结构体的逐一成员构造器

// 除了上面提到的默认构造器, 如果结构体没有自定义的构造器, 他们将自动获得一个逐一成员的构造器, 即使结构体的存储型属性没有默认值

// 逐一成员构造器使用来初始化结构体新实例成员属性的快捷方法, 我们在调用逐一成员构造器是, 通过与成员属性名相同的参数名进行传值 来完成 对成员属性的初始赋值

struct Size{

let ss = "44"

var width = 0.0, height = 0.0

}

let twoByTwo = Size.init(width: 2.0, height: 2.0)

// 值类型的构造器代理

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

// 构造器代理的实现规则和形式 在 值类型 和 类类型中有所不同, 值类型 (结构体和枚举类型) 不支持继承, 所以构造器代理的过程相对简单, 因为他们只能代理给自己的其他构造器, 类则不同, 它可以继承自 其他类, 这个意味着类有责任保证其所有继承的存储属性 在构造是也能正确的初始化,

// 对于值类型, 你可以使用 self.init 在自定义的构造器中引用相同类型中其他构造器, 并且你只能在构造器背部调用 self.init

// 如果你为 某个值类型 定义了一个自定义的 构造器, 你将无法访问到默认构造器, 这种限制可以防止 你为 值类型增加一个额外的且 十分复杂的构造器之后, 任然有人错误的使用自动生成的构造器

// 下面的例子将定义一个结构体 Rect ,用来代表几何矩形. 这个例子需要两个辅助的 结构体 Size 和 Pointm 他们各自为其所有的属性提供了初始值 0.0

struct Point{

var x = 0.0,y = 0.0

}

// 你可以通过以下三种方式 Rect 创建实例 -- 使用被初始化为 默认值的 origin  和 size 属性来初始化, 或者指定的 origin 和 size 实例来初始化, 或者指定 center 和 size 来初始化,

struct Rect{

var origin = Point()

var size = Size()

init() {

}

init(origin: Point, size: Size) {

self.origin = origin

self.size = size

}

init(center: Point,size: Size) {

let originX = center.x - (size.width / 2)

let originY = center.y - (size.height / 2)

self.init(origin: Point(x:originX,y:originY), size: size)

}

}

// 第一个 Rect 构造器 init(), 在功能上跟没有自定义构造器是自动获得的默认构造器是一样的, 这个构造器是一个空函数, 使用一对大括号 {} 来表示,它没有执行任何构造过程, 调用这个构造器将返回一个 Rect 实例, 他的 origin 和 size 属性都使用定义是的 默认值 Point(x:0.0,y:0.0) 和 Size(width:0.0,height:0.0)

let basicRect = Rect.init()

// 第二个 Rect 构造器 init(origin:size:), 在功能上跟结构体在没有自定义构造器时获得的 逐一成员构造器是一样的. 这个构造器只是简单地将 origin 和 size 的参数赋值给对应的存储类型

let originRect = Rect.init(origin: Point.init(x: 2.0, y: 2.0), size: Size.init(width: 5.0, height: 5.0))

// 第三个 Rect 构造器 init(center:size:) 稍微复杂一些, 它先通过 center 和 size 的值计算出 origin 的坐标, 然后再调用 (或者说代理给), init(origin:size:) 构造器来讲新的 origin 和 size 值赋值到对应的属性中:

let centerRect = Rect.init(center: Point.init(x: 4.0, y: 4.0), size: Size.init(width: 3.0, height: 3.0))

// 构造器 init(center:size:) 可以直接将 origin 和 size 的新值赋值到对应的属性中, 然后, 利用恰好提供了相关功能的现有构造器会 更为方便, 构造器init(center:size)的意图也会更加清晰

swift 学习- 15 -- 构造过程 01的更多相关文章

  1. swift 学习- 16 -- 构造过程 02

    // 类的继承 和 构造过程 // 类里面的所有的存储型属性 -- 包括所有继承自父类的属性 -- 都必须在构造过程中设置初始值 // Swift  为类类型提供了 两种构造器来确保实例中所有的存储属 ...

  2. swift学习笔记之-构造过程

    //构造过程 import UIKit /* 构造过程(Initialization): 1.构造过程是使用类.结构体或枚举类型的一个实例的准备过程.在新实例可用前必须执行这个过程,具体操作包括设置实 ...

  3. Swift 的类、结构体、枚举等的构造过程Initialization(下)

    类的继承和构造过程 类里面的全部存储型属性--包含全部继承自父类的属性--都必须在构造过程中设置初始值. Swift 提供了两种类型的类构造器来确保全部类实例中存储型属性都能获得初始值,它们各自是指定 ...

  4. 【Swift学习】Swift编程之旅---构造方法(十八)

    初始化是为了使用某个类.结构体或枚举类型的实例而进行的准备过程.这个过程包括为每个存储的属性设置一个初始值,然后执行新实例所需的任何其他设置或初始化.   初始化是通过定义构造器(Initialize ...

  5. Swift 学习笔记 (二)

    原创:转载请注明出处 41.闭包表达式语法(Closure Expression Syntax) 闭包表达式语法有如下一般形式: { (parameters) -> returnType in ...

  6. Swift 学习- 02 -- 基础部分2

    class NamedShape{ var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name ...

  7. Welcome-to-Swift-14构造过程(Initialization)

    构造过程是为了使用某个类.结构体或枚举类型的实例而进行的准备过程.这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务. 构造过程是通过定义构造器(Initializers)来实 ...

  8. Swift学习——Swift解释特定的基础(七)

    Implicitly Unwrapped Optionals    隐式解析选项 如上所述.可选意味着常数或变量"没有值".通过可选if声明来推断是否存在值,假设有值析值. 有时候 ...

  9. Swift 学习笔记 (一)

    原创: 转载请注明出处 Extention try catch rxSwift internal  public  private var  let as       as? 强转 ? ! didSe ...

随机推荐

  1. [译]使用mediatR的notification来扩展的的应用

    原文 你不希望在controller里面出现任何领域知识 开发者经常有这样的疑问"这个代码应该放在哪呢?"应该使用仓储还是query类?.... 怎么去实现职责分离和单一职责呢? ...

  2. oracle 对对表匹配的进行修改匹配不上的可以进行新增 (MERGE INTO)

    MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句. 通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询, 连接条件匹配上的进行UPDATE,无法匹配 ...

  3. ES6走一波 Proxy/Reflect

    Proxy:像拦截器,对目标对象修改等进行拦截,是一种元编程(meta programming),即修改JS语言本身. //生成proxy实例,两个参数都是对象,targetObj是要拦截的目标对象, ...

  4. JAVA进阶3

    间歇性混吃等死,持续性踌躇满志系列-------------第3天 1.局部内部类 局部内部类是指在类的方法中定义的内部类,它的作用范围也是在这个方法体内. class SellOutClass{ p ...

  5. shell编程 之 流程控制(条件语句和循环语句)

    1 if ...else... 基本格式: if condition then commend else commend fi 当然也可以写到一行,用[ ]表明边界,用:表示分行.比如: if [ $ ...

  6. ubuntu14.04安装Anaconda

    1  安装anaconda 为了安装python等各种依赖包,我安装了Anaconda工具包,在清华源下载了Anaconda的镜像 1.1  下载anaconda 如果用python2.7,就下载An ...

  7. nodejs -Router

    Node 用 request 事件来处理请求响应,事件内使用分支语句处理不同路径的请求,而 Express 封装了这些操作,使得代码简洁优雅 但如果请求路径变多,都写在 app.js 文件里的话,就会 ...

  8. MFC修改对话框标题

    对话框标题栏内容为静态 直接在对话框属性"常规"的"Caption"中修改. 动态生成对话框标题栏内容 SetWindowText()函数就可以 CString ...

  9. Linux网络 - 数据包的接收过程【转】

    转自:https://segmentfault.com/a/1190000008836467 本文将介绍在Linux系统中,数据包是如何一步一步从网卡传到进程手中的. 如果英文没有问题,强烈建议阅读后 ...

  10. Linux 文件系统IO性能优化【转】

    转自:https://blog.csdn.net/doitsjz/article/details/50837569 对于LINUX SA来说,服务器性能是需要我们特别关注的,包括CPU.IO.内存等等 ...