以前我对于copy方法的理解都是分配一块新的内存然后进行内容复制,但其实不同的类有不同的方式:
1,对于NSArray,不会新分配一个内存,而只是将原来对象的地址返回给新对象,并将对象的引用计数加1。如下代码:
NSArray *arr1 = @[@1, @2];
NSLog(@"arr1RetainCount:%ld", arr1.retainCount);
NSArray *arr2 = [arr1 copy];
NSLog(@"arr1RetainCount:%ld", arr1.retainCount);
输出结果:
同时查看arr1和arr2的内存地址,发现是相同的,这就验证了上面的说法。
仔细想想,发现NSArray的复制确实不需要重新建一个对象。假设我们重新分配了内存来新建一个和原来一模一样的对象,其实是造成了内存的浪费,因为它和原来一模一样,而NSArray是没有任何方法可以改变里面的内容的(区别于NSMutableArray),所以没有必要新建对象。同样的,这个也适用于NSString的copy方法,因为NSString对象也不会更改。
2,假如原来的对象是Mutable类型的,或者方法是MutableCopy,只要符合其中一点,都是新建对象,那么原来的对象的引用计数就不会加1了。再来分析原因:假如原先对象是Mutable类型的,那么它本身会改变,假如是MutableCopy,那么后面的对象需要改变(因为有很多改变类里面内容的方法),这样,假如还是用原来的对象的话,那么就不是拷贝了。拷贝原本的含义都是要新建一个对象的,但是因为NSString和NSArray无法更改内存里面的内容,所以可以使用同一个,节省了内存。
3,插一点,假如新建两个NSString的对象,如果用常量赋值给它们,地址还是一样的,比如:
NSString *str3 = @"1";
NSString *str4 = @"1";
但是假如使用方法创建的话就不是相同地址了,比如:
NSString *str3 = [NSString stringWithFormat:@"1"];
NSString *str4 = [NSString stringWithFormat:@"1"];
第一种方式是用了常量来赋值,编译器对它进行了优化,只需要使用一个对象,至于存放的位置,我也不太清楚,有可能是放在堆里面,也有可能是放在存放常量的内存区。而第二种方式是程序自己开辟内存块存放对象,是放在堆里面的。我的理解是这样的,有可能会有问题,希望大家能指正。