Swift 引用类型和值类型

swift中类型主要分两类,分别是值类型和引用类型。这两种类型的功能类似于OC中的深拷贝和浅拷贝。

类型定义 定义类型
值类型 每个实例保留其数据的唯一副本 struct、enum和tuple
引用类型 实例共享数据的单个副本 class

值类型

值类型通常被定义为 struct、enum和tuple。他的主要特点是,每个实例都保留其数据的唯一副本,通俗点说修改 A 实例中的值不会影响到 B 实例。如下所示

1
2
3
4
5
6
7
8
9
10
11
struct S {
var data = 1
}

func valueTypeMethod() {
var a = S()
let b = a
print("\(a.data),\(b.data)") // 1,1
a.data = 2 //改变a中的值
print("\(a.data),\(b.data)") // 2,1
}

引用类型

引用类型通常被定义为 class。他主要的特点是,实例共享数据的单个副本,通俗点说修改 A 实例中的值会影响到 B 实例。如下所示:

1
2
3
4
5
6
7
8
9
10
11
class C {
var data = 1
}

func referenceTypeMethod() {
var a = C()
let b = a
print("\(a.data),\(b.data)") // 1,1
a.data = 2 //改变a中的值
print("\(a.data),\(b.data)") // 2,2
}

为什么会存在这两种类型

swift 为什么会同时存在引用类型和值类型,引用类型是不是能满足一切,那为什么还有值类型呢?

想想如果在多线程环境中使用引用类型,此时我们始终获得一个唯一的实例,但是不同的线程可能会同时对实例进行,这时可能会产生难以预料的错误,而这种错误很难进行调试分析。如果是值类型,我们可以通过分析不同的实例,来帮我们轻松的查找和推理代码中出现的问题。

还有一种情况是当实例中没有数据可进行更改时,值类型和引用类型的行为是完全相同的。如果某个类完全不可变,可能会更有价值,swift 中要实现这样的类可以通过结合不可变的属性和避免公开状态的API来实现。而它目前没有提供任何语言机制来实现对结构和枚举的不可变性。OC 中许多累被设计成不可变例如 NSURL。

两种类型如何选择?

在 OC 中,许多 API 都是 NSObject 的子类,当我们在swift中新建一个类型时,如何去选择?

选择值类型

  1. 实例数据间进行 == 比较有意义
  2. 副本具有独立的状态
  3. 数据将在多个线程中使用

选择引用类型

  1. 实例之间进行 === 比较有意义
  2. 实例内数据的变化需要共享

以上内容参考以下文章

Value and Reference Types