//***********swift学习之24--构造过程--***************************

/*

构造过程:将某个类/结构体/枚举类型实例化而进行的准备过程。

这个过程包含:为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。

Swift 构造函数使用 init()方法。(构造器)

与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。

类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作。

存储型属性的初始赋值

类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值。

存储属性在构造器中赋值时,它们的值是被直接设置的,不会触发任何属性观测器。

存储属性在构造器中赋值流程:

a:创建初始值。

b:在属性定义中指定默认属性值。

c:初始化实例,并调用 init() 方法。

*/

// 实例

// 初始化:以下结构体定义了一个不带参数的构造器 init,并将存储型属性 length 和 breadth 的值初始化为 6 和 12:

struct rectangle {

var length: Double

var breadth: Double

init() {

// 以在构造器中为存储型属性设置 初始值

length = 6

breadth = 12

}

}

var area = rectangle()

print("矩形面积为 \(area.length*area.breadth)")

// 默认属性值

// 在属性声明时为其设置 默认值。

// 使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型。

struct rectangle1 {

// 设置默认值

var length = 6

var breadth = 12

}

var area11 = rectangle1()

print("矩形的面积为 \(area11.length*area11.breadth)")

// 带参数的构造器 如下所示:

// circle 圆的面积

struct circle {

var pai = 3.14

var radius: Double

var area: Double

// 构造器1

init(fromRadius radius: Double) {

self.radius = radius

area = pai * radius * radius

}

// 构造器2

init(fromR r: Double) {

self.radius = r

area = pai * radius * radius

}

}

let ar = circle(fromRadius:2)

print("面积为: \(ar.area)")

let are = circle(fromR:10)

print("面积为: \(are.area)")

// 没有外部名称参数

// 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线_来显示描述它的外部名。

struct Rectanglett {

let length: Double?

init(frombreadth breadth: Double) {

length = breadth * 10

}

init(frombre bre: Double) {

length = bre * 30

}

//不提供外部名字

init(_ area: Double) {

length = area

}

}

// 调用不提供外部名字

let rectarea = Rectanglett(180.0)

print("面积为: \(rectarea.length)")

/*

只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。

对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。

尽管 length 属性现在是常量,我们仍然可以在其类的构造器中设置它的值:

*/

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

// 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。

// 我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。

// 下面例子中定义了一个结构体 Rectangle,它包含两个属性 length 和 breadth。Swift 可以根据这两个属性的初始赋值100.0 、200.0自动推导出它们的类型Double。

struct Rectangleaa {

var length = 100.0, breadth = 200.0

}

let areaaa = Rectangleaa(length: 24.0, breadth: 32.0)

print("矩形的长: \(areaaa.length)")

print("矩形的宽: \(areaaa.breadth)")

// 由于这两个存储型属性都有默认值,结构体 Rectangle 自动获得了一个逐一成员构造器 init(width:height:)。 你可以用它来为 Rectangle 创建新的实例。

/*

值类型的构造器代理

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

以下实例中,Rect 结构体调用了 Size 和 Point 的构造过程

*/

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()

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)

}

}

// origin和size属性都使用定义时的默认值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0):

let basicRect = Rect()

print("Size 结构体初始值: \(basicRect.size.width, basicRect.size.height) ")

print("Rect 结构体初始值: \(basicRect.origin.x, basicRect.origin.y) ")

// 将origin和size的参数值赋给对应的存储型属性

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),

size: Size(width: 5.0, height: 5.0))

print("Size 结构体初始值: \(originRect.size.width, originRect.size.height) ")

print("Rect 结构体初始值: \(originRect.origin.x, originRect.origin.y) ")

//先通过center和size的值计算出origin的坐标。

//然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

size: Size(width: 3.0, height: 3.0))

print("Size 结构体初始值: \(centerRect.size.width, centerRect.size.height) ")

print("Rect 结构体初始值: \(centerRect.origin.x, centerRect.origin.y) ")

// 指定构造器实例

// 初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。

// 每一个类都必须拥有至少一个指定构造器

class mainClasstt {

var no1 : Int // 局部存储变量

init(no1 : Int) {

self.no1 = no1 // 初始化

}

}

class subClasstt : mainClasstt {

var no2 : Int // 新的子类存储变量

init(no1 : Int, no2 : Int) {

self.no2 = no2 // 初始化

super.init(no1:no1) // 初始化超类

}

}

let res = mainClasstt(no1: 10)

let res2 = subClasstt(no1: 10, no2: 20)

print("res 为: \(res.no1)")

print("res2 为: \(res2.no1)")

print("res2 为: \(res2.no2)")

// 构造器的继承和重载

// Swift 中的子类不会默认继承父类的构造器。

// 父类的构造器仅在确定和安全的情况下被继承。

// 重写一个父类指定构造器时,override修饰符。

class FatherClass {

var corners = 4

var description: String {

return "\(corners) 边"

}

}

let rectanglett = FatherClass()

print("矩形:\(rectanglett.description)")

class SonClass:FatherClass {

//    override init () { //重载构造器

//        super.init()

//        corners = 5   // 父类的属性

//    }

}

let sonClass = SonClass()

print("corners: \(sonClass.corners)")

print("五角型: \(sonClass.description)")

// 指定构造器和便利构造器实例 的例子

class MainClass {

var name: String

init(name: String) {

self.name = name

}

convenience init() {

self.init(name: "[匿名]")

}

}

let main = MainClass(name: "Runoob")

print("MainClass 名字为: \(main.name)")

let main2 = MainClass()

print("没有对应名字: \(main2.name)")

class ChildClass: MainClass {

var count: Int

init(name: String, count: Int) {

self.count = count

super.init(name: name)

}

override convenience init(name: String) {

self.init(name: name, count: 1)

}

}

let sub = ChildClass(name: "Runoob")

print("MainClass 名字为: \(sub.name)")

let sub2 = ChildClass(name: "Runoob", count: 3)

print("count 变量: \(sub2.count)")

// 可失败构造器 init!

// 如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器。

// 通常在init关键字后添加问号的方式(init?)来定义一个可失败构造器,但你也可以使用通过在init后面添加惊叹号的方式来定义一个可失败构造器(init!)。实例如下:

struct StudRecord {

let stname: String

init!(stname: String) {

if stname.isEmpty {return nil }

self.stname = stname

}

}

let stmark = StudRecord(stname: "Runoob")

if let name = stmark {

print("指定了学生名")

}

let blankname = StudRecord(stname: "")

if blankname == nil {

print("学生名为空")

}

// 三种类型的可失败构造器

// a:结构体 -- 可失败构造器

// 1.变量初始化失败可能的原因有:

// 2.传入无效的参数值。

// 3.缺少某种所需的外部资源。

// 4.没有满足特定条件。

/*

实例

下例中,定义了一个名为Animal的结构体,其中有一个名为species(种)的,String类型的常量属性。

同时该结构体还定义了一个,带一个String类型参数species的,可失败构造器。这个可失败构造器,被用来检查传入的参数是否为一个空字符串,如果为空字符串,则该可失败构造器,构建对象失败,否则成功。

*/

struct Animal {

let species: String

init?(species: String) {

if species.isEmpty { return nil }

self.species = species

}

}

// 通过该可失败构造器来构建一个Animal的对象,并检查其构建过程是否成功

// someCreature 的类型是 Animal? 而不是 Animal

let someCreature = Animal(species: "长颈鹿")

// 打印 "动物初始化为长颈鹿"

if let giraffe = someCreature {

print("动物初始化为\(giraffe.species)")

}

// 枚举类型的可失败构造器

/*

你可以通过构造一个带一个或多个参数的可失败构造器,来获取枚举类型中特定的枚举成员。

实例

下例中,定义了一个名为TemperatureUnit的枚举类型。其中包含了三个可能的枚举成员(Kelvin,Celsius,和 Fahrenheit)和一个被用来找到Character值所对应的枚举成员的可失败构造器:

*/

enum TemperatureUnit {

// 开尔文,摄氏,华氏

case Kelvin, Celsius, Fahrenheit

init?(symbol: Character) {

switch symbol {

case "K":

self = .Kelvin

case "C":

self = .Celsius

case "F":

self = .Fahrenheit

default:

return nil

}

}

}

let fahrenheitUnit = TemperatureUnit(symbol: "F")

if fahrenheitUnit != nil {

print("这是一个已定义的温度单位,所以初始化成功。")

}

let unknownUnit = TemperatureUnit(symbol: "X")

if unknownUnit == nil {

print("这不是一个已定义的温度单位,所以初始化失败。")

}

// 类的可失败构造器

/*

值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。

但是,类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。

实例

下例子中,定义了一个名为 StudRecord 的类,因为 studname 属性是一个常量,所以一旦 StudRecord 类构造成功,studname 属性肯定有一个非nil的值。

*/

class StuRecord {

let studname: String!

init?(studname: String) {

self.studname = studname

if studname.isEmpty {

print("构造失败")

return nil

}

}

}

var strParame = "失败构造器"

strParame = ""

if let stname = StuRecord(studname: strParame) {

print("模块为 \(stname.studname)")

}

// 覆盖(重写)一个可失败构造器

/*

子类的可失败构造器 可以 重写父类的可失败构造器。

也可以用子类的非可失败构造器 重写父类的可失败构造器。

你可以用一个非可失败构造器覆盖一个可失败构造器,但反过来却行不通。

一个非可失败的构造器永远也不能代理调用一个可失败构造器。

实例

以下实例描述了可失败与非可失败构造器:

*/

class Planet {

var name: String

init(name: String) {

self.name = name

}

convenience init() {

self.init(name: "[No Planets]")

}

}

let plName = Planet(name: "Mercury")

print("行星的名字是: \(plName.name)")

let noplName = Planet()

print("没有这个名字的行星: \(noplName.name)")

class planets: Planet {

var count: Int

init(name: String, count: Int) {

self.count = count

super.init(name: name)

}

override convenience init(name: String) {

self.init(name: name, count: 1)

}

}

swift_024(Swift 的构造过程)相关推荐

  1. Swift之深入解析构造过程和析构过程

    一.Swift 构造过程 构造过程是为了使用某个类.结构体或枚举类型的实例而进行的准备过程,这个过程包含了为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务. Swift 构造函数使用 in ...

  2. swift 笔记 (十四) —— 构造过程

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

  3. BigInteger类实例的构造过程——JDK源码解析

    最近看了下JDK1.6版本的BigInteger类,仔细研究了下大整数实例的构造过程,现在把自己的所得所想分享给大家. 首先,为什么需要大整数类?简单的说就是因为内部的数据类型能表示的最大数是64位长 ...

  4. oracle构造过程实例

    包的构造过程是没有任何名称的,它是在实现了包的其他过程之后,以begin开始,以end结束的部分. 1,包头 create or replace package pkg_emp is   minsal ...

  5. 依次输入表(30,15,28,20,24,10,68,35,50)中的元素,生成一棵平衡的二叉排序树。请画出构造过程,并在其中注明每一次平衡化的类型(LL型、RR型、LR型、RL型)

    题目 依次输入表(30,  15,  28,  20,  24,  10,  68,  35,  50)中的元素,生成一棵平衡的二叉排序树. 请画出构造过程,并在其中注明每一次平衡化的类型(LL型.R ...

  6. java ctor_.ctor,.cctor 以及 对象的构造过程

    .ctor: 简述:构造函数,在类被实例化时,它会被自动调用. 当C#的类被编译后,在IL代码中会出现一个名为.ctor的方法,它就是我们的构造函数,对应C#中的构造函数.且看下面的代码: publi ...

  7. java中的逸出是什么意思,发布和逸出-构造过程中使this引用逸出

    1.什么是this对象 this就是该对象实例本身 2.何为发布和逸出 发布,就是把对象暴露给他人,这就是为什么会需要用到封装,不能预料到其他第三方会如何使用对象,一不小心可能就被玩坏了 逸出,把不应 ...

  8. Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。

    Huffman树在编码中有着广泛的应用.在这里,我们只关心Huffman树的构造过程. 给出一列数{pi}={p0, p1, -, pn-1},用这列数构造Huffman树的过程如下: 1. 找到{p ...

  9. 第三章 软件构造过程与配置管理

    第三章 软件构造过程与配置管理 第三章 软件构造过程与配置管理 Software Development Lifecycle(SDLC)软件开发生命周期 From 0 to 1 从无到有 From 1 ...

最新文章

  1. BEM 实战之微信个人页面
  2. 更改innodb_page_size状态值
  3. PAT (Basic Level) Practice (中文)C++ python 语言实现 —— 题解目录
  4. lan口配置 petalinux_PetaLinux安装及使用
  5. Nike Kyrie 1 Performance Review
  6. python3.5安装pip_win10上python3.5.2第三方库安装(运用pip)
  7. Loj#3130-「COCI 2018.12」Praktični【线性基】
  8. mysql查询雇员部门和性别_数据库管理系统MySQL实验
  9. 【Day05】Html5 有哪些新特性?如何处理 Html5 新标签的浏览器兼容问题?如何区分 Html 和 Html5?
  10. Android + Appium 自动化测试完整的环境配置及代码详解
  11. kali没有arpspoof命令_windows环境下使用python3命令
  12. chkconfig用法
  13. 数学知识——高数速查手册
  14. 福利工具,如何利用小程序免费下载积分文件呢?【第02期】
  15. cvte软件测试在线测评,CVTE笔试题总结归纳
  16. 怎么更改计算机信息,修改电脑oem信息的方法 如何修改oem电脑配置信息
  17. C语言英尺和英寸换算米
  18. 阿里云磁盘异常爆满的原因排查及解决方法
  19. 迅为4418/6818开发板 Yocto 系统烧写
  20. Java模拟微信发红包,一看就会

热门文章

  1. 10.11杭州Clouder lab 十分钟搭建共享应用 2:如何通过日志服务实现用户的日志收集与分析...
  2. LeetCode 之 Merge Sorted Array(排序)
  3. 《机器人与数字人:基于MATLAB的建模与控制》——2.3节指数映射和k过程
  4. Ubuntu Server下配置UTF-8中文/英文环境
  5. uva 10152 ShellSort
  6. 上班族漫画(转收藏)
  7. NotePad++列编辑
  8. luogu 1471
  9. 克服拖延的11种方法
  10. hihocoder #1333 : 平衡树·Splay2