★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布

前言:

本篇仅为视频学习笔记

短接上篇:
★ iOS高级:Swift入门精讲③ 01 swift编程-04-枚举-03关联值内存分布


 enum Season {
     case spring, summer, autumn, winter
 }

那么,这个家伙又占多大呢?这个时候我们来看一下:

★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布_第1张图片

注意看,打印出来的结果为:1、1、1,也就是说,到时候,我定义一个Season的枚举变量,它只占一个字节。

var s = Season.spring

思考一下,为什么只占一个字节就够了。原因,你这个枚举特别的简单,那到时候,我存储在内存中,你不觉得我用一个字节就能表示清楚你存储的是spring、是summer、是autumn、是winter吗?

举个例子,比如说它底层呢?给它编一个号倒时候存储内存的时候把spring当作0,那么这个summer当作是1,autumn当作是2,这个winter当作是3,也就是说到时候,s这一个字节内存里面,存储的就是这4个数字,要么存储0,要么存储1,要么存储2,要么存储3。思考一下,是不是就能表达枚举的真实内容呢?所以,这个很好理解。一个字节就够了。

一个s字节就能表示清楚是 case spring, summer, autumn, winter 这四个中的哪一个。var s = Season.spring底层用一个字节就可以搞定了。因为你取值范围就4个而已,只是存储4个值,你用一个字节不就搞定了吗?

你的值,也不是非常非常大的, case spring = 23232323,你才可能用8个字节来存储。

下面为整体代码:

  enum Season {
      case spring, summer, autumn, winter
  }
  
   var s = Season.spring
  MemoryLayout.size        // 1,实际用到的空间大小
  MemoryLayout.stride      // 1,分配占用的空间大小
  MemoryLayout.alignment   // 1,对齐参数

★ 如果改成下面这样打印出来的还是1

 enum Season: Int {
    case spring = 1, summer, autumn, winter
}

   var s = Season.spring

MemoryLayout.size        // 1,实际用到的空间大小
MemoryLayout.stride      // 1,分配占用的空间大小
MemoryLayout.alignment   // 1,对齐参数

为什么呢?这就是关联值、和原始值的一个区别:

★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布_第2张图片
关联值

如上面这个,叫做关联值。相当于我number这个成员,是跟具体的其它类型(Int,Int,Int,Int) 关联在一起存储的。这个叫关联值。

下面这个呢,叫做原始值


★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布_第3张图片
原始值

也就是我们在定义成员的时候,就给它搞一个默认的家伙,跟它关联在一起,有种这样的感觉,就是预先关联在一起。

★ 那么,它们(关联值、原始值) 本质有什么区别呢?
其实区别,非常非常简单,如果是关联值case number(Int,Int,Int,Int),是将你传进来的这个关联的值,直接存储到枚举变量的内存里面。如下:

var pwd = Password.number(5, 6, 4, 7)

是将传进来的5, 6, 4, 7存储在了变量pwd里面。这种东西叫做关联值,关联值是什么,是可以传进不同的值进来。也就是说,有一天我定义一个新的枚举变量,是不是我可以传不同的值啊。如下:

var pwd1 = Password.number(2, 4, 13, 0)  // 占用32字节
var pwd2 = Password.number(23, 43, 133,30)  // 占用32字节

所以,你想一想,既然这个关联值,是以后可以传入不同的值的,那不就意味着什么?意味着每一个枚举变量,有自己的内存去存储(23, 43, 133,30) 这些值啊。总体来说,这个关联值是由外面传进来的,而且,每次传的可能不一样,所以每一个枚举变量要有单独的内存去存储这些关联值(23, 43, 133,30) 。所以,关联值的特点是什么?是将传进来的这些关联值(23, 43, 133,30),直接存储到我们枚举变量pwd2的内存当中。

所以,你这个枚举变量是关联值的话,你的内存绝对跟将来要存储的关联值大小有关的。

接下来,再看一下原始值,原始值是固定死的。如下:

 enum Season: Int {
     case spring = 1, summer = 2, autumn = 3, winter = 4
 }

思考一下,上面这种东西 = 1叫做原始值,原始值是什么意思呢?它会跟你的成员永远绑定在一起,比如说spring以后就是1 ,summer以后就是2 ,autumn以后就是3 ,winter以后就是4。

说白了,它是不允许我们这个spring以后再传一个19,再传一个20绑定在一起。这是不允许的。如下:

 var s = Season.spring(19)

也就是,说白了,如下:

 var s = Season.spring
 
 var s1 = Season.spring
 
 var s2 = Season.spring

这个三个枚举变量都是全新的枚举变量吗?大家都是spring,但是我告诉你这三个的原始值都是1.不允许你自定义。但是如果我们的case number(Int,Int,Int,Int) 是一个关联值的话,那么每一个枚举成员都是可以传值的。所以,像这种情况,你的关联值肯定存储在枚举变量的内存里面。

但是,这个原始值就不一样了,原始值这个东西是固定死的。 case spring = 1, summer = 2, autumn = 3, winter = 4。

思考一下,既然原始值这个东西是固定死的,那么你觉得有必要这莫做吗?举个例子:

 enum Season: String {
     case spring = "1", summer = "2", autumn = "3", winter = "4"
 }
 
 var s = Season.spring
 
 var s1 = Season.spring
 
 var s2 = Season.spring
 
 MemoryLayout.size        // 1,实际用到的空间大小
 MemoryLayout.stride      // 1,分配占用的空间大小
 MemoryLayout.alignment   // 1,对齐参数

先说清楚String类型占用16个字节,那么有的人就会异想天开,既然spring原始值是1这个字符串,是不是1这个字符串,到时候会存储到枚举变量里面嘛?如果按照这个思路,去思考问题。

那么,刚才说过,1个字符串占用16个字节,那你想把这个字符串存到枚举变量,那你的意思不就是说,到时候,我定义一个Season.spring,赋值给这个枚举变量s,你的意思是,到时候s这个枚举变量,它里面存储的1,占用16个字节。到时候,又来一个Season.spring,这个s1这个枚举变量存储的是1,也占用16个字节。依次如下。你觉得有必要吗?大家s\s1\s2对应的原始值是固定死的。都是字符串1。你干嘛,把这个大家公共的都是1的这个家伙,存储到枚举变量里面去呢?没有这个必要。

你真正想拿到枚举值,直接s2.rawValue拿到这个值就好了。也就是说它真正底层存储,不像大家想象的这么浪费。如果你是这么想的,它是将字符串1存到这个s变量里面去,那就说明这个真是浪费内存,编译器是没有这么傻的。

那么,编译器怎么做呢?还是按照我刚刚的做法,尽管 enum Season: String这里面写了一个String,代表你的原始值是字符串类型,但是它依然是给 case spring = "1", summer = "2", autumn = "3", winter = "4"这些家伙标记一个序号来存储的。相当于这个spring 标记为0,autumn标为1,autumn标为2,winter标为3。也就是说,s\s1\s2这三个枚举变量都各占1个字节。

那么,这个s这1个字节里面其实存储的就是0这个值,因为我说了spring你可以把它当作0,但它究竟是从0开始,还是从1开始,到时候,我们窥探内存才知道。现在,我们假设从0开始。

好,那么我们定义s1 这个变量,它也只占1个字节,而且,这个字节里存储的值其实就是0。s2也是相同。那么这三个枚举变量,其实都占一个值。它只占一个字节。如果你想拿到对应的字符串,你可以s2.rawValue就可以了。


★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布_第4张图片

★ 原始值是不会,存储到枚举变量里面的,只有关联值会。

你可能感兴趣的:(★ iOS高级:Swift入门精讲③ 01 swift编程-05-枚举-04原始值内存分布)