-
拷贝
-
目的: 产生一个副本对象
-
比如桌面上有一个文件夹iOS,iOS文件夹中有一个名字叫做 iOS底层笔记二.docx的文件 .
-
command + C, command + V . 会有一个 iOS底层笔记二的副本.docx 的文件。
-
这两个文件,我可以任意改变其中的一个文件,另一个文件不会受到影响。
-
特点:跟原对象互不影响
- 修改原对象,不会影响副本对象
- 修改副本对象,不会影响原对象
-
有一个对象 Person *p,它里面有大于10个的属性
-
需求1,
- 创建一个新的对象 Person *p2, 它的属性跟 p对象的属性一模一样
- 这个时候就可以用 copy。
- 这种类似于 克隆技术
如何使用 copy ?
- 系统中自带的类型 有 copy 功能 。如: NSString , NSArray, NSDictionary
NSString *str;
NSString *str2 = [str copy];
NSString *str2 = [str mutableCopy];
NSArray *arr;
NSArray *arr2 = [arr copy];
NSDictionary *dic;
NSDictionary *dic2 = [dic copy];
iOS 提供了2个拷贝方法
copy:
- 不可变拷贝,产生不可变副本
mutableCopy:
- 可变拷贝,产生可变副本
NSString *str1 = [NSString stringWithFormat:@"test"];
NSString * str2 = [str1 copy];
NSMutableString * str3 = [str1 mutableCopy];
// copy 和 mutableCopy 都会产生副本
NSLog(@"%@, %@, %@",str1, str2, str3);
// 打印结果: test, test, test
- 但是 str2 和 str3 的类型是不一样的。
copy
产生的是不可变副本,所以类型还是NSString
*mutableCopy
产生的是可变副本,所以类型是NSMutableString
.
如何证明 str3
是可变字符串(类型是 NSMutableString
)
[str3 appendString: @"123"];
NSLog(@"%@",str3);
// 打印结果: test123
测试 str2 是不是 可变类型 ?
// 原本应该写为:NSString * str2 = [str1 copy];
NSmutableString *str2 = [str1 copy];
[str2 appendString: @"123"];
NSLog(@"%@",str3);
// 打印结果: 报错,因为 NSString 没有 appendString 方法。
那如果str1 在创建的时候就是 可变字符串呢
NSMuatbleString *str1 = [NSMuatbleString stringWithFormat:@"test"];
NSString * str2 = [str1 copy];
NSMuatbleString * str3 = [str1 mutableCopy];
- 不管 str1 创建的时候是 可变类型还是不可变类型。在调用 copy 的时候,返回的类型都是不可变类型。调用 mutableCopy 的时候,返回的类型都是 可变类型。
oc 对象的内存管理
- 在 iOS 中,使用 引用计数 来管理 OC 对象的内存
- 一个新创建的OC 对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间
- 调用 retain 会让 OC 对象的引用计数 + 1 , 调用 release 会让 OC 对象的引用计数 -1.
- 内存管理的经验总结
- 当调用 alloc,new,copy,mutableCopy 方法返回了一个对象,在不需要这个对象时,要调用 release 或 autorelease来释放它。
- 想拥有某个对象,就让它的引用计数 + 1, 不想在拥有某个对象,就让它的引用计数 -1。
- 可以通过以下私有函数来查看自动释放池的情况
- extern void _objc_autoreleasePoolPrint(void);
当调用 alloc,new,copy,mutableCopy 方法返回了一个对象,在不需要这个对象时,要调用 release 或 autorelease来释放它。
NSMuatbleString *str1 = [NSMuatbleString stringWithFormat:@"test"];
// 需要释放 str2
NSString * str2 = [str1 copy];
// 需要释放 str3
NSMuatbleString * str3 = [str1 mutableCopy];
mrc 的时候,需要 用下面的方式写代码,才没有内存泄露
NSString *str1 = [NSString stringWithFormat:@"text"];
- 这种写法,不使用 release。
打印这三个变量的地址:
可以看到 str1 和 str2 的内存地址一样。str3 的内存地址不一样。
内存图:
为什么会 这样,因为 str1 和 str2 的都是不可变的。所以没有必要 在创建一个 test来浪费内存。
在不可变的情况下,使用 copy 相当于 retain。
也就是说 NSString * str2 = [str1 copy];
= NSString * str2 = [str1 retain];
NSString *Str1 = [[NSString alloc] initWithFormat:@"text"];
打印 str1.retainCount, 结果是 -1.这是因为 str1 是 tagged pointer 。
解决办法: 把 test 变成很长很长的字符串。
堆地址:
tagged pointer
深拷贝和浅拷贝
- 深拷贝:内容拷贝,产生新的对象
- 浅拷贝:指针拷贝,没有产生新的对象。