Swift结构体内存初探之写时复制

        Swift赋予了结构体很多余类相同的特性,以至于Swift推荐在程序中使用结构体来存储结构化数据(关于类与结构体的区别,以及在使用时的选择不在本文讨论范围)。Swift标准库中大部分都是通过结构体实现的,典型的是Array,Dictionry,Set,String。

       结构体是值类型,区别于类(引用类型,ARC内存管理)。当你将一个结构体赋值给一个新的变量时或者作为参数传递给一个函数时,Swift会对结构体做一次复制,如果每次赋值或者传参都要复制,似乎很昂贵。Swift没那么傻,其实标准库中有很多结构体都使用了写时复制的技术。图-1以数组为例:

Swift结构体内存初探之写时复制_第1张图片
图-1


     通过Playground的截图看出:arrA赋值给arrB后,两个数组的内存地址是相同的,然后对arrA添加元素,arrA的指针起始地址发生了改变,arrB没有变。说明,arrB确实是arrA的复制,但是只当arrA发生改变时才会为arrA分配新的内存空间。其实无论是否把arrA赋值给arrB,只要arrA发生改变,就会重新为arrA分配内存地址,这是因为值语义的不变性,相当于把新的值语义[1,2,3]赋值给值类型arrA,而不是改变原来的值语义[1,2],arrA指针变化前后的起始地址是不同的可以看出。

      编译器对于值类型的复制优化和值语义类型的写时复制并不一样。我们在自定义结构体时,如果结构体包含引用类型的属性,需要自己要实现写时复制。

Swift结构体内存初探之写时复制_第2张图片
图-2

      如图-2:Company结构体中包含引用类型属性employee,对comA的职员姓名修改其实只是修改引用指向的对象,引用本身不变,所以甚至可以用let来修饰。我们看到comB的职员姓名也相应修改了,Company结构体不具备我们想要的值语义。下面我们动手实现Company的写时复制,如图-3:

Swift结构体内存初探之写时复制_第3张图片
图-3

      首先,我们需要Employee是可拷贝的,我们定义一个Copyable协议,然后让Employee遵守这个协议。然后声明一个employeeForWriting的计算属性,changeEmployeeName方法每次执行时就会返回一个employee的拷贝,对这个拷贝进行修改。于是我们完成了自定义结构体的写时复制。

你可能感兴趣的:(Swift结构体内存初探之写时复制)