iOS 为啥不用NSMutableArray取代NSArray

NSArray 和 NSMutableArray 的底层结构应该是差不多的。区别从名字就可以看到,NSArray 不可变,而 NSMutableArray 可变。NSArray 因为不可变,实现起来会更简单些。
iOS 这种设计是适当的,明确区分了不可变的数据结构和可变的数据结构。不可变有时也叫只读。 不可变是个约束限制,施加这种限制可以减少不确定性。比如:
doSomething(NSMubaleArray* array);这样的接口,doSomething 里面就有可能修改 array 的内容,这样当使用这种函数的时候,就需要考虑数据被修改应该怎么办?是不是应该先复制一份,防止修改呢?这样就多了不确定性。而这种接口:
doSomething(NSArray* array);就没有这个问题。
你可能会说,我在实现 doSomething 的时候小心一点,保证内部不会被修改,并且用注释说明,调用这函数的时候不会被修改,这样其它人使用的时候就不用复制了。但是这种小心是不可信的,有可能出错就一定会出错。不应该想着写注释要他人注意,而应该想办法从根源杜绝问题。
另外,不可变结构附带有如下好处:
功能单一,实现起来会更简单。没有修改的数据的接口,就从根源防止了数据无意中被修改。因为不会被修改,更容易被缓存复用。因为不可变,只读,多线程访问的时候,也不会发生一边读一边写的情况,也就没有同步的问题,也就不用上锁。闲话一句,设计类接口的时候,功能并非越多越好,不要想着接口以后可能有用就先加上,而应该想着接口现在没有必要,就直接去掉。这点可能跟初学编程的人想的不一样。有时还会嫌某个类接口太多,而会将其用另一个类封装起来,只提供少数接口。
其实不单是 iOS 开发,其它场合都会区分可变和不可变的。比如 C++ 中的 const。swift 中的 let, Java 中的 final ,打开文件指定是否可读写。这些都是施加约束限制,无限制的所谓自由意味着混乱。

■网友
NSArray可以看成是线程安全,可变数组非线程安全
■网友
前面从使用角度回答的都很精彩,我从内部实现角度回答一下吧,水平有限敬请指正。
NSArray 的底层使用了“类簇”的设计模式,也就是说,底层其实有很多具体的实现类。
先回答你的疑问,之所以不用NSMutableArray取代NSArray,抛开减少开发者错用的角度,单纯从设计角度考虑,是因为节约资源(空间、时间)。
一、NSArray 不可变版本,实际实现时分为几种不同的实现类,比如(不是全部):
1.只有一个元素的话,使用__NSSingleObjectArrayI类,它的结构很简单,只有一个 id类型的指针
2.多个元素的话,使用__NSArrayI类,结构是NSUInteger _used; 和 id _list; _used是数组的元素个数,调用时,返回的就是_used的值。id _list可以理解为一个存储id对象的buff
二、而NSMutableArray使用的是一个叫做“环形缓冲区”的结构,即可以认为是一个逻辑上首尾相接的结构。这样的好处是,在首尾插入或者删除元素时,时间复杂度为O(1)(普通C语言数组的特点就是,虽然读取很快,但插入很慢,例如在首部插入,需要移动数组中全部元素),即便在非首尾位置插入,也会尽可能移动数据更少一边的元素。
显然,从结构复杂度上看,NSMutableArray不论是从创建时间,还是占用内存都是比不可变数组多的,所以追求极致效率的程序猿们怎么能容忍这样的事情呢?

■网友
不可变的好处已经有诸多回答了。
从接口设计上来说,
NSArray是用来传递这样的信息:“这是一个数组,并且其包含的内容改变”;NSMutableArray是用来传递这样的信息:“这事一个数组,其包含的内容可以被改变”。
【iOS 为啥不用NSMutableArray取代NSArray】 从这个层面来看,用NSMutableArray来取代NSArray会导致你在接口设计上丧失表达“其包含的内容改变”这一约束的能力。


推荐阅读