·
·
文章目录
  1. 写在前面
  2. 值类型和引用类型
    1. 有什么区别?
    2. 为什么选择值类型更安全?
  3. struct 和 class
    1. 关于引用类型和继承关系
    2. 关于 immutable 变量
    3. 关于 mutating function

详解 Swift 中 class 和 struct

写在前面

Swift 中 struct、enum 都有了很大的变化,这边从基本概念开始分析,如值类型和引用类型的原理、内存管理机制等等来分析三者在 Swift 语言中的异同。

值类型和引用类型

首先提到的是 iOS 中的内存管理机制的问题,在 iOS 中内存对象主要有两类,值类型和引用类型。值类型就是 int、float、struct、enum、tuple 等基本数据类型,引用类型就是继承自 NSObject 的对象,通常是类对象,我们做内存管理的时候就是对这种对象进行管理。

为什么值类型不需要进行内存管理,而引用类型需要进行内存管理呢? 因为两种方式的内存分配机制不一样,值类型存储在栈当中,在内存中连续的内存空间,遵循后进先出(LIFO)的原则;而引用类型存储在堆当中,存储空间是随机的,对象之间留有空白空间,会产生空间碎片,需要手动进行管理。

有什么区别?

值类型基本特征就是复制数据,不管是在赋值、初始化还是参数传递的过程中,并且为这个数据创建独立的实例。

1
2
3
4
5
6
7
struct S {
var value = 0
}
var a = S()
var b = a // a被复制给了b
a.value = 1 // a改变了, b没有
println("\(a.value), \(b.value)") // "0, 1"

引用类型在赋值、初始化还是参数传递的过程中其实创建了实例,但是实例的指针指向和原来实例同样的内存地址,所以说修改其中一个示例数据的时候,另一个实例数据也同样会被修改。

1
2
3
4
5
6
7
class C {
var value = 0
}
var a = C()
var b = a // a被复制给了b
x.value = 1 // a和b都被修改了
println("\(a.value), \(b.value)") // "1, 1"

为什么选择值类型更安全?

选择值类型而不是引用类型的一个主要原因是能让你的代码变得更加简单。你在任何情况下用一个值类型,都能够假设你的其他代码不会使它改变,这通常在多线程环境中很有用,如果一个线程中使用的数据被另一个线程给意外的修改了,这通常会产生非常严重的Bug,且相当难以调试。在 Objective-C 中 NSArray、NSDictionary 都是属于 NS 类,而 Swift 中 Array、Dictionary 都是属于 struct 类型,显然在后者在多线程编程中更加安全。

在 iOS 中通常创建一个类,继承自 NSObject 的时候,这就已经是引用类型,我们发现在 Objective-C 中建立 Model 的时候选择的总是继承自 NSObject 的类,而在 Swift 中通常使用 struct 来进行 Model 来建立,重要的一点原因是因为 Swift 语言中,struct、enum 都支持了定义方法,极大的扩展了可用性,再加上值类型的安全性,成了 Model 最好的选择。

struct 和 class

我们接下来会详细分析 struct 和 class 的异同。

关于引用类型和继承关系

  • struct 是值引用,class 是类型引用;
  • struct 没有继承,class 有继承功能;

关于第一点的区别,上面已经详细讲过原理,不再赘述。第二点区别,struct 没有继承,这是因为 Swift 在本质上来说是面向协议(Protocol Oriented)的语言。

关于 immutable 变量

我们都知道在 Swift 语言中,通过 let 和 var 就能够来控制不可变和可变,struct 也是遵循该规则。

1
2
let s = S()
s.value = 1 // 该方法会抛出错误,Cannot assign to property: 's' is a 'let' constant

而在 class 中,let 规则是无法延续的。

1
2
let c = C()
c.value = 1 // 可以直接赋值,且不抛出错误

关于 mutating function

1
2
3
4
5
6
7
struct S {
var value = 0

mutating func change(_ value: Int){
self.value = value
}
}
1
2
3
4
5
6
7
class C {
var value = 0

func change(_ value: Int){
self.value = value
}
}

我们发现两者的区别在于 struct 的方法中添加了 mutating 关键字,这是因为在 struct 中 property 是不允许在方法中修改的,如果需要在方法中修改就需要加上关键字。一般这种情况出现较少,最近在写栈数据结构的时候碰巧遇到了,比如实现栈的 pop、push 方法,就需要对栈的 property 做修改。

**版权声明**

Ivan’s Blog by Ivan Ye is licensed under a Creative Commons BY-NC-ND 4.0 International License.
叶帆创作并维护的叶帆的博客博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证

本文首发于Ivan’s Blog | 叶帆的博客博客( http://yeziahehe.com ),版权所有,侵权必究。

本文链接:http://yeziahehe.com/2017/09/11/class_struct_enum/

支持一下
扫一扫,支持yeziahehe
  • 微信扫一扫
  • 支付宝扫一扫