swift简单总结(二十四)—— 构造过程

版本记录

版本号 时间
V1.0 2017.07.29

前言

我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体
6. swift简单总结(六)—— 协议扩展与泛型
7. swift简单总结(七)—— 数据类型
8. swift简单总结(八)—— 别名、布尔值与元组
9. swift简单总结(九)—— 可选值和断言
10. swift简单总结(十)—— 运算符
11. swift简单总结(十一)—— 字符串和字符
12. swift简单总结(十二)—— 集合类型之数组
13. swift简单总结(十三)—— 集合类型之字典
14. swift简单总结(十四)—— 控制流
15. swift简单总结(十五)—— 控制转移语句
16. swift简单总结(十六)—— 函数
17. swift简单总结(十七)—— 闭包(Closures)
18. swift简单总结(十八)—— 枚举
19. swift简单总结(十九)—— 类和结构体
20. swift简单总结(二十)—— 属性
21. swift简单总结(二十一)—— 方法
22. swift简单总结(二十二)—— 下标脚本
23. swift简单总结(二十三)—— 继承

构造过程 - Initialization

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

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

类实例可以通过析构器(deinitializer)在类实例释放之前执行特定的清楚工作。

这一篇从下面几个方面讲解:

  • 存储型属性的初始值
  • 定制化构造过程
  • 默认构造器
  • 值类型的构造器代理

存储型属性的初始赋值

类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值,存储型属性的值不能处于一个未知的状态。可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。

注意:为存储型属性设置值时,它们的值时被直接设置的,不会触发任何属性观测器(property observer)

1. 构造器

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

下面我们看一个例子。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        var f = Fahrenheit()
        print("temperature is \(f.temperature)")
    }
}

struct Fahrenheit {
    var temperature : Double
    init() {
        temperature = 32.0
    }
}

下面看输出结果

temperature is 32.0

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

2. 默认属性值

如果一个属性总是使用同一个初始值,可以为其设置一个默认值,无论定义默认值还是在构造器中赋值,最终它们实现的效果是一样的,只不过默认值将属性的初始化和属性的声明结合的更紧密,使用默认值能让你的构造器更简洁和更清晰。

你可以使用更简单的方式在定义结构体Fahrenheit时为属性temperature设置默认值,具体如下代码所示。

struct Fahrenheit {
    var temperature : 32.0
}

定制化构造过程

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

1. 构造函数

你可以在定义构造器时提供构造函数,为其提供定制化构造所需值的类型和名字。构造器参数的功能和语法跟函数和方法参数相同。

下面看一个简单例子。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        let boillingPointOfWater = Celsuis(formFahrenheit: 212.0)
        let freezePointOfWater = Celsuis(fromKelvin: 273.15)
        print(boillingPointOfWater)
        print(freezePointOfWater)
    }
}

struct Celsuis {
    var temperatureInCelsuis : Double = 0.0
    init(formFahrenheit fahrenheit : Double) {
        temperatureInCelsuis = (fahrenheit - 32.0) / 1.0
    }
    
    init(fromKelvin kelvin : Double) {
        temperatureInCelsuis = kelvin - 273.15
    }
}

下面我们看结果输出

Celsuis(temperatureInCelsuis: 180.0)
Celsuis(temperatureInCelsuis: 0.0)

可以发现,我们可以定义多个构造器,并且可以设置外部参数和内部参数,这里设置的是两个构造器。

2. 内部和外部参数名

其实,这个功能上个例子已经可以看到,在构造器中设置内部参数和外部参数。如果在定义构造器的时候没有提供参数的外部名字,swift会为每个构造器的参数自动生成一个和内部名字相同的外部名,就相当于在每个构造参数之前加一个哈希符号。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let color = Color(red: 1.0, green: 1.0, blue: 1.0)
        print(color.red)
        print(color.green)
        print(color.blue)
    }
}

struct Color {
    var red = 0.0, green = 0.0, blue = 0.0
    init(red : Double, green : Double, blue : Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }
}

下面看输出结果

1.0
1.0
1.0

3. 可选属性类型

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

看一下下面的例子。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let cheeseQuestion = SurveyQuestion(text: "Do you like me?")
        cheeseQuestion.ask()
        cheeseQuestion.response = "YES, I do!"
        print(cheeseQuestion.response)
    }
}

class SurveyQuestion{
    var text : String
    var response : String?
    init(text : String) {
        self.text = text
    }
    
    func ask(){
        print(text)
    }
}

下面看输出结果

Do you like me?
Optional("YES, I do!")

这里,response就是可选属性,当SurveyQuestion实例化时,它将自动赋值为空nil,表明暂时不存在此字符串。

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

只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值,对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改,不能再子类中修改,下面看一个例子。

class SurveyQuestion{
    let text : String
    var response : String?
    init(text : String) {
        self.text = text
    }
    
    func ask(){
        print(text)
    }
}

这里

 let text : String

定义了常量属性,并且在构造器中进行了修改。


默认构造器

swift为所有属性已提供默认值的且自身没有定义任何构造器的结构体或基类,提供一个默认的构造器。下面我们在看一个例子。

class ShoppingList{
    var name : String?
    var quatity = 1
    var purchased = false
}

这里ShoppingList的所有属性都有默认值,它将自动获得一个可以为所有属性设置默认值的默认构造器。

1. 结构体的逐一成员构造器

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

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let size = Size(width: 2.0, height: 2.0)
    }
}

struct Size {
    var width = 0.0, height = 0.0
}

下面,Size是一个结构体,它包含两个属性widthheight,结构体自动获得一个逐一成员构造器init(width:height),可以为Size创建新的实例。


值类型的构造器代理

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

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

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

注意:如果你为某个值类型定义了一个定制构造器,你将无法访问到默认构造器(如果是结构体,则无法访问注意对象构造器),防止定义了定制的构造器,别人还是错误的使用自动生成的构造器。

下面看一个例子。

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 * 0.5
        let originY = center.y - size.height * 0.5
        self.init(origin: Point(x : originX, y : originY), size: size)
    }
}

这里用到了三个构造器,如下:

  • 第一个构造器init(),在功能上根没有自定义构造器时自动获得的默认构造器是一样的,大括号里什么都没做,调用这个构造器就会返回一个Rect实例,它的originsize属性都使用自定义的默认值Point(x = 0.0, y = 0.0)和Size (width = 0.0, height = 0.0)

下面我们调用一下

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let basicRect = Rect()
        print(basicRect.origin)
        print(basicRect.size)
    }
}

下面看输出结果

Point(x: 0.0, y: 0.0)
Size(width: 0.0, height: 0.0)
  • 第二个Rect构造器init(origin : size : ),在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的,这个构造器只是简单的将originsize参数值赋值给对应的存储型属性。

下面我们调用一下。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray

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

    }
}

下面看输出结果

Point(x: 2.0, y: 2.0)
Size(width: 5.0, height: 5.0)
  • 第三个Rect构造器init(center : size :),这个复杂一点,先通过centersize计算origin坐标,然后调用或代理给init(origin : size : )构造器构造出新的originsize

下面我们调用一下。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGray
        
        let centerRect = Rect(center: Point(x : 4.0, y : 4.0), size: Size(width: 3.0, height: 3.0))
        print(centerRect.origin)
        print(centerRect.size)
    }
}

下面看一下输出结果

Point(x: 2.5, y: 2.5)
Size(width: 3.0, height: 3.0)

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容