iOS的一些集合类比如NSArray, NSDictionary是immutable的,刚开始做iOS的同学可能因为不知情会直接使用NSArray或NSDictionary进行集合类的增删操作,从而导致unrecognized selector的crash. 而在iOS中如果要使用带有mutable功能的NSArray, NSDictionary,就必须使用NSMutableArray,NSMutableDictionary了. 习惯了Java的同学们可能没有这个概念,因为Java中就的集合类都是mutable的,而这些iOS开发同学们都习以为常了,今天想要谈的是NSObject下面的copy和mutableCopy方法。
日常开发中,大部分的情形是拿到一个NSArray或者NSDictionary,然后要往里面做添加或者删除操作时,先调用mutableCopy来获取一个mutable的copy,再对这个copy进行添加或者删除。那如果拿到的是NSMutableArray或者NSMutableDictionary,那调用copy返回的究竟是mutable的还是immutable的?先不卖关子,返回的是immutable的,这里坑就来了,如果我拿着NSMutableArray或者NSMutableDictionary调用copy产生的拷贝,天真地以为拿了一个mutable的集合类进行操作,然后悲剧就来了,crash…crash…crash…
查了下Apple Doc, copy的描述如下,
Returns the object returned by copyWithZone:.
再看下copyWithZone:,
The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object.
这下清楚了,copy返回的永远是immutable,不管调用者是immutable还是mutable的。
于是,想到了另一个日常开发场景,有些属性在某个类内是mutable的,但为了防止外部修改,对外返回的时候要返回immutable的,这时有一种做法是这样的,
-(NSArray *)someArray
{
NSMutableArray mArray=[NSMutableArray array];
return mArray;
}
这样对外返回的就是向上转型为NSArray类型的对象了,但实际上它还是NSMutableArray类型,如果调用者强行调用NSMutableArray中的方法也是可以的,所以,更彻底的一种做法就可以采用刚才说的方法,
-(NSArray *)someArray
{
NSMutableArray mArray=[NSMutableArray array];
return [mArray copy];
}
这样,外部调用者就对返回的array无计可施了。