[OC Foundation框架

一个对象使用copy或mutableCopy方法可以创建对象的副本

1.copy
需要实现NSCopying协议
创建出来的是不可变副本,如NSString, NSArray, NSDictionary
 
(1)不可变对象调用copy  (NSSring除外)
不会产生新的对象,而是返回对象本身,相当于retain,计数器+1
属于浅拷贝
 
复制代码
 1         NSArray *arr1 = [NSArray arrayWithObjects:@"张三", @"李四", nil];
 2         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
 3         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1
 4 
 5        
 6         NSArray *arr2 = [arr1 copy];
 7         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
 8         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 2  <-- 浅拷贝,相当于retain, retainCount+1
 9         NSLog(@"arr2.addr: %p", arr2); //0x1002052b0 <-- 浅拷贝,依旧指向同一个对象
10         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 2 <-- 浅拷贝,还是原来对象的retainCount
复制代码
 
(2)可变对象调用copy (NSMutableString会拷贝出一个NSString”常量对象")
返回一个不可变对象,但是不是原来的对象,属于深拷贝
复制代码
 1         NSMutableArray *arr1 = [NSMutableArray array];
 2         [arr1 addObject:@"123"];
 3         [arr1 addObject:@"abc"];
 4         NSLog(@"arr1.addr: %p", arr1); // 0x100204840
 5         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1
 6        
 7        
 8         NSMutableArray *arr2 = [arr1 copy];
 9         NSLog(@"arr1.addr: %p", arr1); // 0x100204840
10         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
11         NSLog(@"arr2.addr: %p", arr2); // 0x100300000 <-- 深拷贝,开辟了新的内存空间,拷贝出来的实际对象是NSArray
12         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 1 <-- 深拷贝,新的对象retainCount独立
复制代码
 
(3)重点: NSString的特殊性
由于使用了 @“” 进行初始化,数据存放在了常量池
 
因为NSString指向字符串常量,系统不会收回,也不会对其作引用计数,即使我们对NSString变量如何retain或release,retainCount都是-1 (无符号最大值)
复制代码
 1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
 2         NSLog(@"str1.addr: %p", str1); // 0x100001030
 3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存
 4        
 5         NSString *str2 = [str1 copy];
 6         NSLog(@"str1.addr: %p", str1); // 0x100001030
 7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
 8         NSLog(@"str2.addr: %p", str2); // 0x100001030 <-- 拷贝之后的变量依旧指向原来的常量
 9         NSLog(@"str2.retainCount: %ld", str2.retainCount); // -1 <-- 原来常量的retainCount
10        
11         [str1 retain];
12         NSLog(@"after retain -> str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
13         [str2 release];
14         NSLog(@"after release -> str2.retainCount: %ld", str2.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
复制代码
 
要使一个NSString变量也有retainCount:
就要是指向另外一个”NSString”对象,而不是字符串常量
1         // 先创建出一个NSString对象,再用另一个指向
2         NSString *str1 = [NSString stringWithFormat:@"abc"];
3         NSLog(@"%ld", str1.retainCount); // -1
4         NSString *str2 = [NSString stringWithString:str1];
5         NSLog(@"%ld", str2.retainCount); // 1
 
(4)copy出来的是不可变对象,如NSMutableString调用copy创建出来的实际是NSString
复制代码
 1         // 这里不能使用 NSMutableString *mstr1 = @"abc", 或者在延迟赋值 mstr1 = @"abc"; 否则同样指向常量池
 2         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
 3         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
 4         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
 5 
 6 
 7         NSMutableString *mstr2 = [mstr1 copy];
 8         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
 9         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
10         NSLog(@"mstr2.addr: %p", mstr2); // 0x63626135 <-- 深拷贝,开辟了新的内存空间,但是指向的实际是一个字符串常量
11         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // -1 <-- 因为其实拷贝出来的是一个字符串常量
复制代码
2.mutableCopy
需要实现NSMutableCopying协议
创建的是可变副本,如NSMutableString, NSMutableArray, NSMutableDictionary
 
(1)不可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
复制代码
1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
2         NSLog(@"str1.addr: %p", str1); // 0x100001030
3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存
4 
5         NSMutableString *mstr2 = [str1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
6         NSLog(@"str1.addr: %p", str1); // 0x100001030
7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 对于字符串常量, 无论是copy, retain, release操作都不会改变retianCount
8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100106460 <-- 深拷贝,开辟新的空间
9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1 <-- 由于是NSMutableString对象,retainCount == 1
复制代码
 
(2)可变对象调用mutableCopy
产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
复制代码
1         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
2         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
3         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
4 
5         NSMutableString *mstr2 = [mstr1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
6         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
7         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100300e90 <-- 深拷贝,开辟新的空间
9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1
复制代码
 
3.自定义类的copy
1 @interface Student : NSObject
2 
3 //copy代表setter会release旧对象,copy新对象
4 @property (nonatomic, copy) NSString *name;
5 
6 @end
 
传入外部NSMutableString对象到student的setter,当外部对象改变的时候,不会改变student中copy来的对象
如果使用retain或者assign,就会影响,因为指向的是同一个对象
==>传入NSMutableString时(成员变量为NSString),一般使用copy策略,其他使用retain
 
(1)实现<NSCopying>
(2)实现 - (id) copyWithZone:(NSZone *) zone
1 - (id)copyWithZone: (NSZone *) zone
2 {
3      Student *stu = [[Student allocWithZone:zone] init];
4      stu.name = self.name;
5      return stu;
6 }
如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
原文地址:https://www.cnblogs.com/wvqusrtg/p/4515328.html