iOS Swift5 构造函数分析(二):init 构造函数在struct与class中的区别

一、前言

上篇《关键字 designated、convenience、required》中,我们了解到了 swift 在构造器这块给我们带来的新特性,结合我们之前的一篇《浅析结构体(struct)与类(class) 》,我们今天就来聊聊在 struct 与 class 中的应用与不同。

二、默认构造器

先来个灵魂拷问:何谓『默认构造器』?
不显式定义给出构造器(构造函数),由系统自动添加生成!(在 Swift 中,默认构造器就是 designated 构造器)

是不是光看文字理解有点困难?那我就来个 demo 演示。

2.1、struct

struct DemoStruct {
    var name: String
    var age: Int
}

没有构造方法(init),但我们可以这么来初始化使用:

struct-before.png

当我们输入『左括号』时,Xcode 自动提示,给了我们一个唯一的初始化方法,这个就是『默认构造器』,我们也可以显式这样来创建:

struct-init.png

即通过 init 构造器来初始化,但同样,Xcode 也提示我们有两个参数。为啥是有参数,而不是无参,例如:DemoStruct.init() ?

2.1.1、逐一成员构造器

这是 Swift 规范:当我们没有显式指定至少一个 init 构造器时,swift 会为我们添加一个默认构造器,该构造器的入参即是 struct 中的所有成员!

上面例子中,我们定义了两个成员,分别是:name 和 age,因此,swift 会按照从上到下,依次将其纳入到默认构造器中,即创建了如下构造器:

swift-struct.png

如果 struct 讲到这里就完了,是不是很没意思?如果你认为这就完了,你就『Too Young Too Simple』了!

如果我们的 struct 中有很多成员变量,虽然 swift 会为我们创建默认构造器,但是,我们在使用时,每个参数都需要传入,使用就会很麻烦,那有没有其它方式呢?例如,初始化时,我只想传 name :

optional.png

上面的代码片段没有报错,运行无任何问题!

我们有三种解决方式:

  • 可选参数默认构造器;
  • 默认参数默认构造器;
  • 扩展构造器;

2.1.2、可选参数默认构造器

param-nil.png

我们看到,age 的类型是 Int? ,但可为 nil;因此,我们可以在初始化时,只需要传入强制必要的参数:

struct-param-nil.png

2.1.3、默认参数默认构造器

名字有点绕,但效果很简单:

param-def.png

2.1.4、扩展构造器

扩展,即 extension ,swift 提供的一种方式,无论是 struct 还是 class 都可以使用:

// 扩展 struct
extension DemoStruct {
    // 重载一个构造器
    // 该构造器调用默认构造器
    init(name: String) {
        self.init(name: name, age: 18)
    }
}

执行结果如下:

struct-result.png

2.2、class

同样,先来定义一个 class,代码如下:

class DemoClass {
    var name: String
    var age: Int
}

如果仅是这样,Xcode 会立即提示报错(类没有构造器):

no-init.png

我们至少需要显式指定(explicit designated)一个构造器,对于 DemoClass,我们要按照类似 struct 的逐一成员构造器那样,定义一个构造器,如果只构造部分成员的构造器,则会如下报错:

not-all-init.png

该错误提示:没有初始化所有的成员。对于这种情况,我们有三种方式来完成:

  • 将 age 设置为可默认为 nil 类型(等同于 2.1.2);
  • 定义 age 时就给定默认值(等同于 2.1.3);
  • 在构造器中给定默认值(如下代码所示);
class DemoClass {
    var name: String
    var age: Int
    
    init(name: String) {
        self.name = name
        // 构造器中给定默认值
        self.age = -1
    }
}

class 要求必需显式指定一个构造器,而 struct 则是由 swift 自动添加。同样,class 也可以通过扩展(extension)来重载构造器(注:扩展类的构造器,是需要便利的,即添加关键字:convenience):

extension DemoClass {
    convenience init(name: String, age: Int) {
        self.init(name: name)
        self.age = age
    }
}

我们执行看下结果:

class-result.png

三、可失败构造器

类似 Kotlin 都有一种类型叫可null类型,Swift 也不甘落后,也有可空类型,而且 Swift 更进一步,允许在创建变量(struct)、对象(class)或枚举时,返回空对象(即创建失败,返回为 nil )。

  • 什么叫空类型?
// T 代表任何类型
// variable 代表变量、对象
var variable: T? = nill

// 例如:
var str: String? = nil // 可 nil 字符串
var num: Int? = nil    // 可 nil 整型
  • 如何定义可失败构造器?

可失败构造器定义非常简单,只需要在 init 后加个问号,即:init? 即可,例如下图:

define-init-nil.png

我们可以看到,我们定义了一个可失败构造器,如果创建 Person 时,传入的字符串是『空字符串』,那么我们就返回 nil,否则就成功创建。从上图中,我们还能发现,可失败构造器的返回类型是:T?,在上面的例子中,返回类型是 Person?,即代表可能为 nil 。

dif-use-init-nil.png

上图是我们的测试代码,执行后打印结果非常清楚。对于 class 或者 enum ,与 struct 类似,我就不再演示,大家可自行测试。

四、个人感想

可人有些朋友要问:为何要花如此大的力气来分析 struct 和 class ?难道就是因为 Swift 新增了 struct 所以才写这些么?

不,因为我在做《iOS Swift5从0到1系列》中,发现每当我实现一些功能时,就会或多或少涉及到一些 Swift 的新特性,虽然这些特性在 Swift 一出来就有,但是,我不确定大家都非常的了解熟悉,因此,但凡涉及到 Swift 中新的知识点,我都会单独开一些分支系列来提前讲解分析,希望大家能够一点一点的学习与吸收,而不是我一下子抛出很多新的知识点,导致大家难以消化吸收,影响心情放中途放弃。

Swift 其实非常简单,我希望让大家和我一起共同成长进步,还可以快乐的交流,并且,本着我的博客中,所有的文章都是高质量,且可吸收(无论是 iOS 还是 Java、Android 或者 H5),因此,我会在讲解主线的同时,穿插不同支线;同时,一篇高质量的博文也要好几天(哪怕是分支内容),因此,希望大家不要心急。

谢谢!

你可能感兴趣的:(iOS Swift5 构造函数分析(二):init 构造函数在struct与class中的区别)