
你瞅啥!瞅你咋地
在 iOS 中,最为重要的一点就是内存管理。而在内存管理时,有时会遇到 copy 出来的对象,是否需要释放内存的情况。所以,本文将讲解下
copy与mutableCopy的用法和区别。
注:关闭 ARC 模式
以下所有内容都将以 NSString 作为例子进行讲解
-
重要规则:
- 目的:类似文件夹,拷贝备份之后,源文件修改不影响copy文件,同时,copy文件修改也不影响源文件。总结:拷贝之后,互不影响
- 不可变对象:copy直接引用计数+1,互相修改也不会影响;mutableCopy的副本能修改,则需生成新的对象;
- 可变对象:copy和mutableCopy的源本能修改,则需生成新的对象。
- 目的:类似文件夹,拷贝备份之后,源文件修改不影响copy文件,同时,copy文件修改也不影响源文件。总结:拷贝之后,互不影响
copy
重点:copy 出来的对象都是不可变对象
// 对于不可变字符串,copy 类似与 retain(浅copy)
NSString *string1 = [[NSString alloc] initWithFormat:@"字符串1"];
NSString *newString1 = [string1 copy];
NSLog(@"%ld", [string1 retainCount]); //2
不可变字符串(字典、集等),copy 操作相当于 retain(指针拷贝)。
这种 copy 方式,不会分配内存,只是让 newString1 持有了 string1 的内存。

不可变对象的copy操作
// 对于可变字符串,copy 会重新开辟空间(深 copy)
NSMutableString *string2 = [[NSMutableString alloc] initWithFormat:@"字符串2"];
NSMutableString *newString2 = [string2 copy];
NSLog(@"%ld", [string2 retainCount]); //1
可变字符串(字典、集等),copy 操作相当于 alloc 并且赋值(内存拷贝)。这种 copy 方式,会重新分配内存。
所以对 newString2 操作(修改、release 等)并不会影响到 string2,因为他们没有在操作同一块内存。

可变对象的copy操作
因为
copy 出来的都是不可变对象,所以这里的 newString2,即使是 NSMutableString 类型,但不能调用可变对象的方法,因为 newString2 已经是不可变对象了。
如果强制调用,程序崩溃,并报错:‘Attempt to mutate immutable object with deleteCharactersInRange:…’ 试图修改一个不可变的对象
mutableCopy
重点:mutableCopy 复制出来的对象都是可变对象,并且对于 NSString 和 NSMutableString 都是内存拷贝(深copy)
// 对于不可变和可变对象,都是内容复制(深 copy)
NSString *string3 = [[NSString alloc] initWithFormat:@"字符串3"];
NSString *newString3 = [string3 mutableCopy];
NSLog(@"%ld", [string3 retainCount]); //1
虽然使用了 NSString 去接收了 mutableCopy 出来的 string3,但是 newString3 依然是一个可变字符串,可以调用可变字符串的方法,但是会报警告,因为子类调用了父类的方法。

不可变对象的mutableCopy操作
NSMutableString *string4 = [[NSMutableString alloc] initWithFormat:@"字符串4"];
NSMutableString *newString4 = [string4 mutableCopy];
NSLog(@"%ld", [string4 retainCount]); // 1
对于可变字符串,mutableCopy 依然是可变。

可变对象的mutableCopy操作
总结
| 对象类型 | copy | mutableCopy |
|---|---|---|
| 不可变对象 | 浅copy,指针复制,返回值不可变 | 深copy,内容复制,返回值可变 |
| 可变对象 | 深copy,内容复制,返回值不可变 | 深copy,内容复制,返回值可变 |