先说结论,定长的值类型,可以保证;其他的(引用及非定长的值类型),不能保证
Swift中,常用let表示静态变量,不可变得;var表示动态变量,可变的。可事实往往并没有这么简单,还要从变量内存存储方式说起。
对于定长的值类型(字符串,集合类型都是变长的),如struct point,都是保存在栈中的,速度快,效率高,自动释放内存,很方便。变长的值类型,引用类型,这俩指针放在栈中间,但是具体的数据都是存放在堆中间的,速度慢一些,需要关心内存状况,但空间大,灵活。
对于存在栈中的变量,可以通过let对其进行限制,限制之后保证其实不可变得,更安全一些。
综上,在编码层面上,值类型数据,可以将成员变量都设成var,这样如果想要一个静态变量,直接将值类型数据设置成let即可保证不被修改,如果需要修改,设置成var即可灵活修改,进退有度。
PS:swift语言默认的是不可变的状态,例如方法传入实参时会进行拷贝,拷贝之后的是不可变的。编码时声明的var变量如果没有修改其具体数值,编译器会提示是否修改成let。看来let肯定是速度更快一些的。
再进一步考虑,不能保证数据的不可变性,当赋值共享某可变数据时,就会产生问题,新的值修改,老的值也会一并被修改。这也不是一定不好,这能在一定程度上共享内存,提高效率,A改变,B自动改变,一定程度上更好的实现需求。但对于不愿意共享这一修改的时候,就会产生问题,类似于OC中浅拷贝,深拷贝区别。
如果想避免上述因共享带来的数据绑定的问题,可以使用copy()方法。比如用B对A进行赋值,如果直接是A=B,这是浅拷贝,会导致上述问题。如果A=B.copy(),是深拷贝,则不会导致上述问题。
以上确实能解决因为拷贝带来的共享的问题。其实不难发现,共享的问题是由于写入导致的,如果是多个变量同时读取同一变量,并不会出问题,但如果写入,就会出问题。因此苹果提出了Copy-on-Write的概念。简单说,就是在写入时自动copy,读取的话不作处理。举个栗子。如果A=B,AB共用一开始B的那一段内存。如果A只是读取,则直接读取B的地址中的数据就可以了。如果A写入了一些数据,则会自动copy出来一份,将需要写入的数据写入到新copy的内存中,并把新的地址赋给A,这样AB都能各自维护自己的数据了。具体代码网上一搜一大把